Now we’re all set to start integrating SES into our application! For the time being, let’s add some pretty standard functionality. When a new user registers, we’ll send her a registration confirmation e-mail. We won’t force her to activate the account in the e-mail; it will simply be a welcome message.
Before we get into the thick of it, we once again have to determine how to make our addresses dynamic, that is, avoid hard-coding them into the application. After all, we want our code to work as well in a dev environment as it does in the production environment. The e-mail address from which registration e-mails are sent should be something like [email protected]. It’s probably a reasonable decision to always assume that the sender should be “donotreply.” We also have the domain stored in an OpsWorks Environment Variable—in the wrong format. There are a few approaches we could take here.
1. Store specific e-mail addresses, such as [email protected] in OpsWorks Environment Variables, and access them programmatically.
2. Use the existing DOMAIN environment variable and programmatically trim
http://www off the beginning, to make it usable in constructing e-mail addresses dynamically.
3. Make a new environment variable for the mail domain and use that.
All three of these approaches (and probably a few others I didn’t think of) are perfectly valid. To keep things simple, we’re going to use the second approach, which will save us the trouble of making new environment variables. At this point, however, you should feel confident about your ability to use any of the preceding approaches to construct an e-mail address dynamically in this context.
Globals
Open /lib/globals.js in your code editor and scroll to the end. After the absoluteURL() function, paste the following:
rootDomain : function(){
return this.awsVariables().domain.replace('http://www.',''); }
This simple function will convert http://www.yourdomain.com to simply yourdomain.com. We call it rootDomain and not just mailDomain, because we could potentially need the root domain at some later point. In the interest of clarity, your globals file should now be as in the following Listing 6-2:
Listing 6-2. Updated Globals
module.exports = { applicationPort : 80, database : function(){ if(process.env.ENVIRONMENT){
var opsworks = require('./../opsworks'); var opsWorksDB = opsworks.db;
var rdsConnection = { host : opsWorksDB.host, port : opsWorksDB.port, database : opsWorksDB.database, user : opsWorksDB.username, password : opsWorksDB.password }; return rdsConnection; } else {
var local = require('./../config/local'); var localConnection = local.db;
return localConnection; } }, awsVariables : function(){ if(process.env.ENVIRONMENT){ var variables = { bucket : process.env.S3BUCKET, domain : process.env.DOMAIN } return variables; } else {
var local = require('./../config/local'); return local.awsVariables;
} },
160
absoluteURL : function(path){ if(this.awsVariables().domain){
return this.awsVariables().domain + '/' + path; } return path; }, rootDomain : function(){ return this.awsVariables().domain.replace('http://www.',''); } }
Mail.js
While we could put most of the rest of our code in the users route, it might make more organizational sense to have a separate class for handling all of our SES transactions. After all, we may want to generate e-mails for other purposes elsewhere in our application. It seems safe to say that e-mail communication deserves its own proxy class.
Create a new file called mail.js in the /lib directory. You could, of course, name it something such as ses.js, if you prefer. First, we must include the dependencies for this file. We’ll require access to our
globals.js, as well as the AWS SDK. At the top of the file, paste the following lines:
var aws = require('aws-sdk'); var globals = require('./globals');
For now, we’re only adding registration e-mails. However, we should structure this file with the assumption that we will be adding other mail functionality in the future. As such, we will be writing two functions: one to construct the content for the registration e-mail and another to send the SES mail.
First, add the sendEmail() function to mail.js (see Listing 6-3). This function will simply send the SES mail with the parameters passed to it. It will remain a private function.
Listing 6-3. sendEmail Function
function sendEmail(params, callback){ if(globals.awsVariables().key){
aws.config.update({ accessKeyId: globals.awsVariables().key, secretAccessKey: globals.awsVariables().secret });
}
var ses = new aws.SES({region:'us-east-1'});
var recipient = params.username + '<' + unescape(params.email) + '>'; var sesParams = { Source: params.messageSource, Destination: { ToAddresses: [recipient], BccAddresses: params.bccAddress }, Message: { Subject: { Data: params.subject, Charset: 'UTF-8' },
Body: { Text: { Data: params.messageText, Charset: 'UTF-8' }, Html: { Data: params.messageHTML, Charset: 'UTF-8' } } }, ReplyToAddresses: [emailSender()] }
ses.sendEmail(sesParams, function(err, data){ callback(err, data);
}); }
You’ll notice a similar pattern to our S3 upload functionality. If an IAM key is found, meaning we’re in the local environment, then call aws.config.update() to use our local credentials. Then, we initialize an instance of SES from the SDK. To use SES, you must set the region as well. In our case, it’s 'us-east-1'. The rest of the function is populating SES parameters with the values sent in the params object. Last, ses. sendEmail() sends the e-mail.
Next, we will create the sendRegistrationConfirmation() function. This function will construct the parameters passed to sendEmail. To add other e-mails to our application, we will merely replicate the
sendRegistrationConfirmation functionality. Add the code in Listing 6-4 to mail.js.
Listing 6-4. sendRegistrationConfirmation Function
function sendRegistrationConfirmation(params, callback){ var emailParams = { username : params.username, email : params.email }; emailParams.messageSource = emailSender(); emailParams.bccAddress = [];
emailParams.subject = 'Registration Confirmation';
emailParams.messageText = ' You have successfully registered for Photoalbums. Your username is ' + emailParams.username + '.'; emailParams.messageHTML = ' You have successfully registered for Photoalbums.
Your username is <strong>' + emailParams.username + '</strong>.'; sendEmail(emailParams, callback);
}
As you can see, we generate our e-mail subject and message in both plain text and HTML. You’ll notice that the messageSource is set to emailSender(). Because we will conceivably be sending multiple system e-mails to users, a reusable function is a good way to minimize code duplication. The emailSender()
162
With the preceding code, we use the root domain originating in the OpsWorks environment variable to construct an e-mail address for the sender.
Last, we have to make sendRegistrationConfirmation() a public method. At the end of the file, add the following line:
exports.sendRegistrationConfirmation = sendRegistrationConfirmation;