In a previous post, I discussed how to use Mandrill in an Angular application. I concluded, however, that I wasn’t sure that I would really use that design pattern in a production environment. In my opinion, it ultimately exposes too much to the client. I mentioned, however, that it would probably be a better route to use the Node API with an Angular client sending it signals. So I thought I’d put together an example that demonstrates just that.
Please note: If you need help setting up your Mandrill account or keys, see my previous post.
#0 – Setup Node Server, Install Mandrill on Node
First things first, you’ll want to setup a node Server that can accept routes, such as with Express.router(). I recommend using body-parser as well.
Then you’ll want to install the Mandrill Node API using NPM.
1 |
npm install mandrill-api |
And then add Mandrill to your Node server.
1 2 |
var mandrill = require('mandrill-api/mandrill'); var mandrill_client = new mandrill.Mandrill('YOUR_API_KEY'); |
So far, so good.
#1 – Setup Factory in Angular
The next step is to setup/replace a factory in Angular that can post information to your Node server. In a minute, we will setup an API route inside of Node that will expose the Mandrill endpoint. For now, just point the $http.post() to your actual location.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
.factory('Mandrill', ['$http', function($http) { return { goodLogin: function(resp, message) { return $http.post('http://localhost:8080/simpleapi/mandrill', { 'data': resp, 'message': message }) .success(function(data, status, headers, config) { return data; }); } }]); |
On success, the factory will return the data that is returned to it by the server to the controller that called it. You will want to setup error handling in addition to what I have here, but there are a lot of project-specific choices to be made in that regard, so I’ll leave it out for the example code.
#2 – Call it from your Controller
Like in my previous post, you will want to call the factory from your controller.
1 2 3 4 5 6 7 |
Mandrill.goodLogin(resp).then(function(data) { if(data.data[0].status === 'sent') { $scope.thisErrorMessage += ' The email was sent.'; } else { $scope.thisErrorMessage += ' This eamil was not sent to the dev team for an unknown reason. Oops.'; } }); |
Using the Promise method, the data returned to the factory by the server is then given back to the controller, where something can be done with it. What I provide here is, admittedly, a weak example, as it simply updates a variable in your View to return a message to the user, but I think the idea should be clear enough. I also covered promises a bit more deeply in that former post.
#3 – Use Mandrill In Node
Finally, we get to Node. To recap, you should have done some basic setups for your server. Keep in mind, that for my example I will be using body-parser.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
var express = require('express'); var app = express(); var router = express.Router(); var bodyParser = require('body-parser'); app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json()); app.use(function(req, res, next) { res.header("Access-Control-Allow-Origin", "*"); res.header("Access-Control-Allow-Headers", "Content-Type"); next(); }); app.use('/simpleapi', router); var apiPort = process.env.PORT || 8888; app.listen(apiPort); |
Then you installed and configured Mandrill as part of your server.
1 2 3 4 5 6 7 |
var express = require('express'); var app = express(); ... var mandrill = require('mandrill-api/mandrill'); var mandrill_client = new mandrill.Mandrill('YOUR_API_KEY'); ... app.listen(apiPort); |
Now comes the time to create the Mandrill endpoint. For the sake of consistency, I have kept the same format of the message as the Angular-only post.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
router.route('/mandrill') .post(function(req, res) { var fromName = 'MWBot'; var toName = 'Matthew'; console.log(req.body); var message = { "html": "<p>Unknown Error Message</p><p>" + req.body.message + "</p><p>Error Code:" + req.body.data.code + "</p>", "text": req.body.data, "subject": "Unknown Error Message", "from_email": fromEmail, "from_name": fromName, "to": [{ "email": toEmail, "name": toName, "type": "to" }], "headers": { "Reply-To": replyTo } }; var async = false; mandrill_client.messages.send({"message": message, "async": async}, function(result) { console.log(result); res.json(result); }, function(e) { console.log('A mandrill error occurred: ' + e.name + ' - ' + e.message); }); }); |
Using body-parser the contents of the post are located in addresses such as req.body.message, which I have used in this basic template. An object variable, message, is constructed with Mandrill API constraints and passed to the mandrill_client.messages.send function. On success, the resulting JSON is passed back to the factory (which is then passed back to the controller). On error, for now, a message is printed to your console.
In reality, it is more likely that the factory would be sending more information to the server – email addresses would be dynamic rather than hardcoded, etc. Additionally, Mandrill’s extensive API options mean there is far more to consider. This example set, however, demonstrates the back and forth.
Using this design pattern, I believe that you can enjoy the enhanced benefit of doing your works more slightly in the background without exposing nearly as much to the client. In my tests, this design pattern performed just as well as a client-only method. It also has the additional benefit of sending from a single IP address point, which allows you to implement one more part of Mandrill’s security offerings.
In the process, however, I came across a third, and probably final, design approach that would take this paradigm one step further – using a secure but light-weight service, such as Firebase, to function as a bus system for sending signals between the client and backend, completely segregating your client and server work altogether. Stay tuned for one more post in this series.