« Previous Tutorial Next Tutorial »

In this tutorial, we’re going to dive into one of the aspects of web development that I hate with the fiery passion of a thousand burning stars: SMTP.

It’s not really that bad, I promise, but trust me when I say that if you’re considering running your own SMTP server to send emails, you probably don’t want to. Not unless you’re already an experienced Server Admin and/or DevOps Engineer, or an incredible masochist. Getting an SMTP server up and running is not inherently difficult, but getting it to properly send actual emails that won’t be sent directly to most users’ spam boxes is more trying. I strongly, strongly recommend using an outside SMTP service.

To that end, that’s what we’re going to discuss today. I’m going to get you set up with Mailgun, a developer-friendly service that gives you a sandbox server that lets you send 300 mails a day to authorized email addresses. You can extend that to 10,000 emails a month, to any email address, by adding a domain to your account. We’re not going to do that today, because we don’t need it yet, but we’ll go through it when we get closer to deploying a finished application.

SO … head for a browser. The first thing we need to do is sign up for Mailgun. To do that, head to http://mailgun.com. Signup’s easy. Either click “Sign Up” in the upper right-hand corner, or the big “Try Mailgun Now” in center-left of the page. You’ll be taken to a relatively straightforward signup form. The only real question here is what to put as your company? Truth is, it doesn’t really matter. You could go with “self-employed” or just your initials. Or, if you have a company you’re learning this stuff for, use that!

Depending on which A/B test you get, you’ll either be asked to give your credit card information right on this page, in which case you can just uncheck the box, or on the next page, in which case you can just skip it. The wording is confusing, but you do not need to enter your credit card to get the free 10k sends per month, just to get some additional benefits. There’s nothing really wrong with entering a credit card here—they’re a reputable company and they’re not going to charge you unless you start sending a ton of emails—but you can just as easily skip the step by clicking the “I’ll do it later” link below.

Once we log in, we’ll see that our account’s not verified. That won’t do, so check the email address you signed up with and click the verification link. You’ll need to give them your mobile phone number so they can send a verification SMS, but don’t worry, they won’t spam you with calls or texts. With that done, we’re almost ready to go, but we’re stuck with a problem. Right now, the only email address we can send emails to is the one we signed up with. If that works for you, great, but it doesn’t work for me. So, first step, click on “domains” in the top menu, then click on your sanbox domain, and then add an authorized recipient. Enter an address that you have access to and are OK with sending test emails to.

Now, you’ll need to access that email so you can verify inclusion as an authorized recipient. Once you’ve authorized your addition to the list, you can head back to the Mailgun control panel. Click on domains, and then your sandbox domain. We’ll need the information on this screen in a few minutes.

First, though, a question: do you have a user for your MusicList app that has the same email address that you just added to the list of authorized users, or the email address that you used when you signed up with Mailgun? If not, you’re going to need to register a new user using that email address. That’s not hard … just go to localhost:3000 and click the register link, then fill in the info. This step’s necessary because, well, we can’t reset the password associated with an email address that doesn’t exist in our DB!

All right, with all that done, we’re ready to write some code. The good news is, we don’t need to write a lot, because there’s a handy module for Mailgun available to us. Head for a terminal window or command prompt, and in your musiclist directory, type

yarn add mailgun-js

And let it do its thing. Then it’s off to Sublime Text, where we need to make some changes to /routes/api/authentication.js. For starters, below line 2, add the following:

const mailgun = require('mailgun-js')({
  apiKey: '',
  domain: '',
});

Now we need to fill in those values. You can find them on your Mailgun control panel, on the screen we previously navigated to, which should still be open in your browser. I’m going to paste some examples in here, but they’re not my actual info, for obvious reason. Here’s roughly what yours should look like:

apiKey: 'key-c7930afd4e505703001da49370b403fa',
domain: 'sandboxdd91bae839780f8a25c8bbe5a98c7636.mailgun.org',

Don’t use those values, though … use your own.

This is problematic. Do you see why? We’re embedding private keys and other potentially sensitive information right into our code. That’s the sort of thing that makes experienced developers, especially those who’ve lived through a security crisis or two, very twitchy. This is fine for a brief local test, but for long-term usage it’s no good. It’d allow anyone with access to the source—which, if you’re running a public github repo, is essentially everyone with an internet connection—the ability to hijack your SMTP server and send out whatever they want to whomever they want. Well, once you’re not running on the test server.

Anyway, it’s fine for now. Let’s move on to our POST to saveresethash on line 83. Specifically, we’re going to add some code to generate and send an email. Starting below line 101, add a padding line, and then this code:

      // Put together the email
      const emailData = {
        from: 'CloseBrace <postmaster@sandboxcc80cfa391224d5d83e5aba2d09b7590.mailgun.org>',
        to: foundUser.email,
        subject: 'Reset Your Password',
        text: `A password reset has been requested for the MusicList account connected to this email address. If you made this request, please click the following link: https://musiclist.com/account/change-password/${foundUser.passwordReset} ... if you didn't make this request, feel free to ignore it!`,
        html: `<p>A password reset has been requested for the MusicList account connected to this email address. If you made this request, please click the following link: <a href="https://musiclist.com/account/change-password/${foundUser.passwordReset}" target="_blank">https://musiclist.com/account/change-password/${foundUser.passwordReset}</a>.</p><p>If you didn't make this request, feel free to ignore it!</p>`,
      };

Pretty obvious what’s going on here, right? It’s just the information our SMTP server will need to send the email. The only things to note, really, are that we’re pulling the email address and password reset hash from foundUser, which makes sense since we want to send the email to an existing user. If we just sent to the address coming in via the form, we might be emailing people who don’t even have accounts with our service.

Side note: I’m not in love with storing big chunks of text in the code like this, but we’re doing it for expediency’s sake. In a larger, more complex application, I’d do my best to break out any English-language text into its own file, and insert those snippets programmatically. That would also help if you eventually wanted to localize your website and have it display information in different languages.

Add another padding line below line 110, and then add the following code:

      // Send it
      mailgun.messages().send(emailData, (error, body) => {
        if (error || !body) {
          result = res.send(JSON.stringify({ error: 'Something went wrong while attempting to send the email. Please try again.' }));
        } else {
          result = res.send(JSON.stringify({ success: true }));
        }
      });

Here we’re using the Mailgun module to send our email, and then reporting success or failure depending on what the module returns. This also leaves us with an extraneous line on 120, below our new code, that looks like this:

      result = res.send(JSON.stringify({ success: true }));

Delete that line entirely or your app will break.

That’s it for code. Save the file, make sure your server’s running, and head for a browser. Either click the log-in link and then the forgot password link, or just navigate to localhost:3000/account/reset-password. Fill in the form using an email address that a) exists in your DB and b) is authorized to receive Mailgun test emails, and then submit. You should get the success message, so check your inbox for the email your app should’ve generated. If all’s gone well, it should show up within a minute or so (usually much less). If not, well, drop a comment and we’ll work things out.

You’re all set, but I recommend NOT checking these changes into github just yet. Before we move on to actually changing a user’s password, we need to address the security flaws mentioned above. In the next tutorial, we’re going to get those secret keys out of our code and into a safer place. Catch you there!

« Previous Tutorial Next Tutorial »