«

»

Aug
02

Sending Emails with Attachement for New S3 Objects

Use Case and Solution

Notify users about a new object (e.g., an image or log file) being added to an S3 bucket by sending an email that contains the new object as attachement. The solution presented here uses AWS Lambda (with S3 as event source), mailcomposer (a Node.JS module) to compose, and finally Amazon’s Simple Email Service (SES) to deliver emails.

Note: At first glance, Amazon’s push notification service SNS seems to be a good choice: S3 offers sending messages to an SNS topic whenever a new object is created out of the box. However, SNS does not allow for Email attachements.

Setting Up an S3-Based Lambda Function

Amazon provides a “S3-get-object” blueprint to make your life easier. The wizard allows you to set up which S3 bucket and event type (in our case, “Object Created“) to monitor.

Sending Emails with S3 Attachement

The wizard creates some error handling code, leaving us with the task to compose and later send the Email. mailcomposer provides a really easy-to-use API for composing emails:

 

var MailComposer = require('mailcomposer').MailComposer,
    mailcomposer = new MailComposer();
var ses =
    new aws.SES({
        accessKeyId: 'XXX',
        secretAccessKey: 'XXX'});
 
// ...
 
s3.getObject(params, function(err, data) {
  if (err) {
    // error handling
  } else {
    mailcomposer.setMessageOption({
      from: 'me@example.com',
      to: 'someone@example.com',
      subject: 'New File',
      body: 's3://' + bucket + '/' + key,
      html: 's3://' + bucket + '/' + key +
            '<br/><img src="cid:' + key + '" />'
    });
    var attachment = {
      contents: data.Body,
      contentType: 'image/png',
      cid: key
    };
    mailcomposer.addAttachment(attachment);
    mailcomposer.buildMessage(function(err, messageSource) {
      if (err) {
        // error handling
      } else {
        ses.sendRawEmail({RawMessage: {Data: messageSource}}, function(err, data) {
          if(err) {
            // error handling
          } else {
              context.done(null, data);
          }
        });
      }
    });
  }
});

Uploading Everything to AWS Lambda

Make sure mailcomposer is installed (“npm install mailcomposer”). ZIP and upload your JavaScript file and “node_modules” folder to AWS Lambda. Make sure that your JavaScript file has the same name as specified under handler (e.g., “index.js” for “index.handler”). Also make sure that your JavaScript file did not end up in a subfolder inside the ZIP file.

Setting SES Rights

Sending Email rights cannot be granted via policies at the moment. Thus, create a new user with a user policy:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "XXX",
      "Effect": "Allow",
      "Action": [
        "ses:SendEmail",
        "ses:SendRawEmail"
      ],
      "Resource": [
        "*"
      ]
    }
  ]
}

Insert this user’s AWS keys in the code above (when creating the SES object).

 

 

 

4 comments

  1. JD says:

    excellent example on using mail composer with lambda. I did have a problem, though and could use a hand. I am unable to run the code correctly as I get syntax error: Unexpected token ILLEGAL on the from: ‘myemailaddress@gmail.com”
    For reference I am using the same from and to reference at gmail as I want to email myself when there is an s3 event. Any idea as to why this would be a problem? I am using mail composer v0.2.9 and I used your code exactly except I put in my AWS keys and my email address.

  2. Stew says:

    After adding all of the modules and executing in lambda I get the following,

    {
    “errorMessage”: “params is not defined”,
    “errorType”: “ReferenceError”,
    “stackTrace”: [
    “Module._compile (module.js:409:26)”,
    “Object.Module._extensions..js (module.js:416:10)”,
    “Module.load (module.js:343:32)”,
    “Function.Module._load (module.js:300:12)”,
    “Module.require (module.js:353:17)”,
    “require (internal/module.js:12:17)”
    ]
    }

    The code it’s referencing is:
    s3.getObject(params, function(err, data) {

  3. Dominik says:

    Sorry for the very late reply, your comment got lost in spam. Maybe there is an invisible character here as described on https://stackoverflow.com/questions/12719859/no-visible-cause-for-unexpected-token-illegal.

  4. Dominik says:

    Hey Stew, that’s odd—do you try to access params in your code? In the above example, params is not used.

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">