Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | import { GetObjectCommand, S3Client } from '@aws-sdk/client-s3'; import { SESv2Client, SendEmailCommand } from '@aws-sdk/client-sesv2'; import { SESEvent, SESEventRecord } from 'aws-lambda'; import PostalMime from 'postal-mime'; import { BUCKET_EMAIL, EMAIL_SOURCE } from '@/types/backend/environment'; import { BILLING_EMAIL_ADDRESS, FORWARD_EMAIL_TO } from '@/utils/backend/hidden-constants'; import { LogLevel, getLogger } from '@/utils/common/logger'; const logger = getLogger('resources/emailHandler'); const s3 = new S3Client(); const ses = new SESv2Client(); async function parseEvent(record: SESEventRecord) { logger.trace('parseEvent', ...arguments); logger.info('Record', record); // Pull out the email information const email = record.ses.mail; logger.info(`Getting email from ${BUCKET_EMAIL()} with key /emails/${email.messageId}`); const rawData = await s3.send(new GetObjectCommand({ Bucket: BUCKET_EMAIL(), Key: `emails/${email.messageId}`, })); if (typeof rawData.Body === 'undefined') { throw new Error('Email body is undefined'); } const emailBody = await rawData.Body.transformToString('utf-8'); // Parse the body const emailParsed = await PostalMime.parse(emailBody); // Forward the email await ses.send(new SendEmailCommand({ Destination: { ToAddresses: [ FORWARD_EMAIL_TO, ], }, ReplyToAddresses: [ emailParsed.from?.address || BILLING_EMAIL_ADDRESS, ], FromEmailAddress: `COFRN Billing <${BILLING_EMAIL_ADDRESS}>`, FromEmailAddressIdentityArn: EMAIL_SOURCE(), Content: { Simple: { Subject: { Data: `[COFRN] ${emailParsed.subject || 'No Subject'}`, }, Body: { ...emailParsed.html ? { Html: { Data: emailParsed.html, }, } : {}, ...emailParsed.text ? { Text: { Data: emailParsed.text, }, } : {}, }, ...emailParsed.attachments && emailParsed.attachments.length > 0 ? { Attachments: emailParsed.attachments.map(attachment => ({ FileName: attachment.filename || 'attachment', ContentType: attachment.mimeType, ContentDisposition: attachment.disposition === 'inline' ? 'INLINE' : 'ATTACHMENT', ContentId: attachment.contentId, RawContent: typeof attachment.content === 'string' ? Buffer.from(attachment.content, attachment.encoding || 'utf8') : new Uint8Array(attachment.content), })), } : {}, }, }, })); } export async function main(event: SESEvent) { logger.trace('main', ...arguments); logger.setLevel(LogLevel.Info); // Get the S3 events const s3EventRecords: SESEventRecord[] = event.Records || []; await Promise.all(s3EventRecords.map(parseEvent)); } |