I am trying to customize the Headers while using the AWS Node.js SDK.
It seems that the sendEmail API endpoint and accompanying SDK method doesn't support customizing Headers.
So the appropiate method to use would be sendRawEmail.
Unfortunately I couldn't find good information or a package that actually helps composing the raw email. Meaning sending both plain text and html formats and creating the message body and headers in accordance to RFC 2822 and RFC 5322.
How would a simple method that composes the raw body written in JavaScript look like?
Here is a barebones function I came up with, which has only the AWS Javascript SDK
as a dependency. One thing I did wrong in the beginning was Base 64 encoding the RawMessage.Data
, but the AWS SDK
already takes care of that.
The empty lines \n
are important as well.
const sendRawEmail = async () => {
// Set up from_name, from_email, to, subject, message_id, plain_text, html and configuration_set variables from database or manually
var date = new Date();
var boundary = `----=_Part${ Math.random().toString().substr( 2 ) }`;
var rawMessage = [
`From: "${ from_name }" <${ from_email }>`, // Can be just the email as well without <>
`To: ${ to }`,
`Subject: ${ subject }`,
`MIME-Version: 1.0`,
`Message-ID: <${ message_id }@eu-west-1.amazonses.com>`, // Will be replaced by SES
`Date: ${ formatDate( date ) }`, // Will be replaced by SES
`Return-Path: <${ message_id }@eu-west-1.amazonses.com>`, // Will be replaced by SES
`Content-Type: multipart/alternative; boundary="${ boundary }"`, // For sending both plaintext & html content
// ... you can add more headers here as decribed in https://docs.aws.amazon.com/ses/latest/DeveloperGuide/header-fields.html
`\n`,
`--${ boundary }`,
`Content-Type: text/plain; charset=UTF-8`,
`Content-Transfer-Encoding: 7bit`,
`\n`,
plain_text,
`--${ boundary }`,
`Content-Type: text/html; charset=UTF-8`,
`Content-Transfer-Encoding: 7bit`,
`\n`,
html,
`\n`,
`--${ boundary }--`
]
// Send the actual email
await ses.sendRawEmail( {
Destinations: [
to
],
RawMessage: {
Data: rawMessage.join( '\n' )
},
Source: from_email, // Must be verified within AWS SES
ConfigurationSetName: configuration_set, // optional AWS SES configuration set for open & click tracking
Tags: [
// ... optional email tags
]
} ).promise();
}
These are the utility methods for formatting the Date Header. You could use as well simply use the moment
library like moment().format('ddd, DD MMM YYYY HH:MM:SS ZZ');
but it doesn't really matter as the Date Header gets overwritten by AWS SES anyway.
// Outputs timezone offset in format ZZ
const getOffset = ( date ) => {
var offset = - date.getTimezoneOffset();
var offsetHours = Math.abs( Math.floor( offset / 60 ) );
var offsetMinutes = Math.abs( offset ) - offsetHours * 60;
var offsetSign = ( offset > 0 ) ? '+' : '-';
return offsetSign + ( '0' + offsetHours ).slice( -2 ) + ( '0' + offsetMinutes ).slice( -2 );
}
// Outputs two digit inputs with leading zero
const leadingZero = ( input ) => ( '0' + input ).slice( -2 );
// Formats date in ddd, DD MMM YYYY HH:MM:SS ZZ
const formatDate = ( date ) => {
var weekdays = [ 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun' ];
var months = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ];
var weekday = weekdays[ date.getDay() ];
var day = leadingZero( date.getDate() );
var month = months[ date.getMonth() ];
var year = date.getFullYear();
var hour = leadingZero( date.getHours() );
var minute = leadingZero( date.getMinutes() );
var second = leadingZero( date.getSeconds() );
var offset = getOffset( date );
return `${ weekday }, ${ day } ${ month } ${ year } ${ hour }:${ minute }:${ second } ${ offset }`;
}