Demo: Meteor-based emailer with geolocation and UA tracking

meteor-logo

In January  we announced that we had partnered up with Meteor to power the email back-end that comes with the Meteor platform. To see an example, check out this event registration form we blogged about recently, but today we want to demo another example of Meteor+Mailgun integration.

Geolocation for email

A few weeks ago we rolled out new parameters to our webhooks to get geolocation and user-agent information for your emails without having to parse UA strings and use IP lookup libraries. We thought it would be fun to build a little app on top of Meteor to show just how easy it is to consume these new parameters.

The demo

Click on the demo below to see it in action and download the app source code from Github so you can play around with it and build your own app or report. After playing around with the demo, come back and we'll go into some more detail about how we built it.

Sending email with Meteor

You can send emails with Mailgun via standard SMTP or with the Mailgun HTTP API. If you just want simple SMTP sending functionality in your Meteor application, start by adding the email package to your project.

>> meteor add email

After running that command you’ll have a default Mailgun account automatically configured and Meteor automatically sets the MAIL_URL environment variable which stores the SMTP configuration. (Check out the email docs on the Meteor site here. As it mentions in the last paragraph, you can test sending even without adding the email package: by default, emails will  output right to the console).

For this demo, we are going to go beyond basic email sending so we're using a Mailgun account directly and use the HTTP API (btw, with the API, Mailgun assembles the MIME server-side so it's a bit easier to deal with, even with simple email sending).

 

Setting things up to send via API

To start grab your API key from the Mailgun control panel, you'll see it when you login.

The API will be called with a simple HTTP POST request. You’ll need to add Meteor’s http package to your project.

>> meteor add http

After the http package is installed, you can perform any HTTP request: GET, POST, PUT, DELETE, etc in your application. 

Getting right to the juicy details: below is an example of how you can send an email with Mailgun via the API:

Meteor.http.post('https://api.mailgun.net/v2/your-api-domain/messages',  
    {auth:"api:" + process.env.MAILGUN_API_KEY,
    params: {"from":"Dev McCool  <mccool@your-domain.com>",
                     "to":[to],
                      "subject":"Behold: the power of Meteor and Mailgun",
                      "html":”A <b>bold</b> greeting goes here”,
                      "h:X-Mailgun-Variables":JSON.stringify({tracking_id:my_tracking_var}),
                      "o:tracking":'True’ }}, function(error, result) {
                      //handle error, result (should be 200 OK)
                     }
           }

Let’s go over a few details here.

You can see we are setting an authentication header with this request using an environment variable called MAILGUN_API_KEY. You can’t set environment variables on the Meteor hosting platform (e.g. meteor deploy) just yet , but if you’re running your Meteor app on Heroku or on your own setup, it’s probably a good idea to keep credentials like your API key tucked away safely in an environment variable. If you want to set an environment variable with Meteor, just do this:

process.env['MAILGUN_API_KEY'] = "my-mailgun-key";

 Also notice that we are adding some custom tracking values, here.

[list type = check]

  • Setting the tracking option to ‘true’ to let Mailgun know to dispatch the webhook when the email is opened.
  • Setting a JSON value to the X-Mailgun-Variable header field. This demonstrates the power of webhooks: we can tuck away some important details or unique values in this header field and get them back when Mailgun dispatches the webhook to our server.

[/list]

In this specific example, the email sending is triggered by a simple HTML button on the client side. We wrapped the email sending functionality in a Meteor method so it can be accessed from the client. See the email sending code here.

Remember to keep important things like API credentials in the server folder of your Meteor application. Files in the server folder aren’t sent to the client. Other files, however, either in the client folder or in the root of the application folder, may find their way to the clients browser.

West side…east side…server side…

When Mailgun detects that our email has been opened, it is going to send a POST request our way. Like any guest, we’ll want the webhook to feel welcome and know that it’s arrived at the right destination: no 404 errors here! Server-side routing is not built into Meteor just yet, but don’t you worry thanks to the flexibility of the platform we can add a simple route for the Mailgun webhook without having to disassemble anything. There’s a bit more code involved with setting up a server-side route:

 

if (Meteor.isServer) {

  var app = __meteor_bootstrap__.app
  var connect = Npm.require('connect');
  var Fiber = Npm.require('fibers');
  var crypto = Npm.require('crypto');

  var router = connect.middleware.router(function(route)
  {
    route.post('/mailgun/receive', function(req, res)
    {
      var raw_post_body = "";
      var post_data = [];

      req.on('data', function (chunk) {
        raw_post_body += chunk.toString();
      });

      req.on('end', function () {
          pairs = raw_post_body.split('&');
          for(var i = 0; i < pairs.length; i++) {
            kv = pairs[i].split('=');
            post_data[kv[0]]=decodeURIComponent((kv[1]+'').replace(/\+/g, '%20'));
          }

          //Verify sender is Mailgun
          var sig = crypto.createHmac('sha256', process.env.MAILGUN_API_KEY).update(post_data['timestamp']+post_data['token']).digest('hex');
          if(sig !== post_data['signature']) {
            res.writeHead(403);
            res.end();
          }
          else {
            Fiber(function() {
                Meteor.call("publishGeo", post_data);
                res.writeHead(200);
                res.end();
            }).run();
          }
      });
    });
  });

  app.use(router);

About halfway down, you’ll see where we perform a quick HMAC calculation to confirm the identity of the sender. Mailgun provides a signature token with each webhook and we can verify validity of this signature by hashing the provided token and timestamp with our API key. It’s not a requirement but just a good idea for any public facing application. This is trivial to do using the HMAC method found in the crypto library.

With this route in place and activated on our server, we can prepare the Mailgun side of things for our webhooks.

Configuring webhooks

If you login to Mailgun, you’ll see the tracking tab at the top of your dashboard. On the bottom of the tracking page, you’ll see a field to enter the destination for the POST requests that Mailgun will send every time an email is opened.

 

Putting it all together

In this demo application we are assigning every browser session a unqiue ID which we include in the Mailgun API call (in that X-Mailgun-Variables HTTP header we sent earlier). When the open webhook comes back, we can inspect not only the geolocation details but we can parse that unique session ID code. This is how we’ll know which browser session the webhook belongs to and we can show the proper location on the map. 

Thanks to the power of the Meteor framework, the browser (the client) can observe any changes to the dataset of the received webhooks.Using the added Collection event on the client, the client is updated immediately when we’ve added another webhook event to our database. Inside the added event, all we have to do is generate a Google Maps location marker using the city, region and country values in the webhook. This is also where we will check the unique ID against our current session ID - if they match, then this marker is placed in front on the map (with z-index) with a red icon.

The last bit of client-side code involves making sure that every marker on the map has a pop-up containing a few other bits of browser details that Mailgun also includes in the webhook data. Mailgun’s tracking webhooks also include such helpful data as operating system, which email client was used to open/read the message, and device type (great for analyzing mobile vs. desktop usage!).

Done!

That’s it: your Meteor application is now ready to receive tracking and open webhooks from Mailgun, securely and reliably.

To see it all in action, visit the demo site and the source on Github.

 

 

comments powered by Disqus

Mailgun Get posts by email

Like what you're reading? Get these posts delivered to your inbox.

No spam, ever.