Created
April 7, 2021 10:50
-
-
Save garlou/51f6840be05364a93a5688761b00aa26 to your computer and use it in GitHub Desktop.
Send raw email with attachment with AWS SES using Typescript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* This solution was built based on stackoverflow answer https://stackoverflow.com/a/54233102 | |
* placed by user https://stackoverflow.com/users/2485910/snowball | |
*/ | |
import AWS from 'aws-sdk'; | |
import {Template} from 'aws-sdk/clients/ses'; | |
interface Attachment { | |
encoding: 'base64'; | |
filename: string; // test.pdf | |
content: string; // base64 value | |
contentType: 'text/plain' | 'application/pdf' | 'image/gif'; | |
} | |
/** | |
* Send email with attachment | |
* @param address | |
* @param template | |
* @param attachment | |
* @returns | |
*/ | |
const sendRawEmail = ( | |
address: string[], | |
template: Template, | |
attachment: Attachment | |
): Promise<any> => { | |
return new Promise((resolve, reject) => { | |
const ses = new AWS.SES({ | |
accessKeyId: process.env.AMZ_ACCESS_KEY, | |
secretAccessKey: process.env.AMZ_SECRET_KEY, | |
region: process.env.REGION, | |
}); | |
const date = new Date(); | |
const boundary = `----=_Part${Math.random().toString().substr(2)}`; | |
const rawMessage = [ | |
`From: ${process.env.FROM_EMAIL}`, // Can be just the email as well without <> | |
`To: ${address[0]}`, | |
`Subject: ${template.SubjectPart}`, | |
`MIME-Version: 1.0`, | |
`Date: ${formatDate(date)}`, // 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`, | |
template.TextPart, | |
`--${boundary}`, | |
`Content-Type: text/html; charset=UTF-8`, | |
`Content-Transfer-Encoding: 7bit`, | |
`\n`, | |
template.HtmlPart, | |
`\n`, | |
`--${boundary}`, | |
`Content-Type: text/plain; name="${attachment.filename}"`, | |
`Content-Description: ${attachment.filename}`, | |
`Content-Disposition: attachment;filename="${attachment.filename}";`, | |
`creation-date="${formatDate(date)}"`, | |
`Content-Transfer-Encoding: ${attachment.encoding}`, | |
`\n`, | |
attachment.content, | |
`\n`, | |
`--${boundary}--`, | |
]; | |
const params: AWS.SES.Types.SendRawEmailRequest = { | |
Destinations: address, | |
RawMessage: { | |
Data: rawMessage.join('\n'), | |
}, | |
Source: process.env.FROM_EMAIL, // Must be verified within AWS SES | |
// ConfigurationSetName: configuration_set, // optional AWS SES configuration set for open & click tracking | |
Tags: [ | |
// ... optional email tags | |
], | |
}; | |
ses.sendRawEmail(params, (err: any, data: any) => { | |
if (err) { | |
return reject(err); | |
} else { | |
return resolve(data); | |
} | |
}); | |
}); | |
}; | |
/** | |
* Outputs timezone offset in format ZZ | |
* @param date | |
* @returns | |
*/ | |
const getOffset = (date: 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 | |
* @param input | |
* @returns | |
*/ | |
const leadingZero = (input: number) => ('0' + input).slice(-2); | |
/** | |
* Formats date in ddd, DD MMM YYYY HH:MM:SS ZZ | |
* @param date | |
* @returns | |
*/ | |
const formatDate = (date: 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}`; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment