UNPKG

@zapal/payload-email-sendgrid

Version:
137 lines (136 loc) 6.14 kB
import { APIError } from 'payload'; /** * Email adapter for [SendGrid](https://sendgrid.com) REST API */ export const sendGridAdapter = (args)=>{ const { apiKey, defaultFromAddress, defaultFromName } = args; const adapter = ()=>({ name: 'sendgrid-rest', defaultFromAddress, defaultFromName, sendEmail: async (message)=>{ // Map the Payload email options to SendGrid email options const sendEmailOptions = mapPayloadEmailToSendGridEmail(message, defaultFromAddress, defaultFromName); const res = await fetch('https://api.sendgrid.com/v3/mail/send', { body: JSON.stringify(sendEmailOptions), headers: { Authorization: `Bearer ${apiKey}`, 'Content-Type': 'application/json' }, method: 'POST' }); if (res.status === 202) return; else { const data = await res.json(); let formattedError = `Error sending email: ${res.status} ${res.statusText}${data.id ? ` (ID: ${data.id})` : ''}.`; (data.errors || []).forEach(({ message, field, help }, idx)=>{ if (field && message) formattedError += `${idx !== 0 ? '; ' : ' '}${field && field !== 'null' ? `Field: ${field}, ` : ''}Message: ${message}${help ? `, Help: ${help} ` : ''}`; }); throw new APIError(formattedError, res.status); } } }); return adapter; }; function mapPayloadEmailToSendGridEmail(message, defaultFromAddress, defaultFromName) { const cc = mapAddresses(message.cc); const bcc = mapAddresses(message.bcc); const attachments = mapAttachments(message.attachments); const email = { // Required from: mapFromAddress(message.from, defaultFromName, defaultFromAddress), subject: message.subject ?? '', personalizations: [ { // Required to: mapAddresses(message.to), // Other To fields cc: cc.length ? cc : undefined, bcc: bcc.length ? cc : undefined } ], // Optional attachments: attachments?.length ? attachments : undefined }; if (message.html || message.text) { email.content = []; if (message.text) email.content.push({ type: 'text/plain', value: message.text.toString?.() || '' }); if (message.html) email.content.push({ type: 'text/html', value: message.html.toString?.() || '' }); } if (message.replyTo) { if (message.replyTo === 'string') { email.reply_to = { email: extractEmailFromAddressString(message.replyTo), name: extractNameFromAddressString(message.replyTo) === message.replyTo ? undefined : extractNameFromAddressString(message.replyTo) }; } else if (Array.isArray(message.replyTo)) { const addresses = mapAddresses(message.replyTo); if (addresses.length) { if (addresses.length > 1) email.reply_to_list = addresses; else email.reply_to = addresses[0]; } } else { email.reply_to = { email: extractEmailFromAddressString(message.replyTo.address), name: message.replyTo.name === message.replyTo.address ? undefined : message.replyTo.name }; } } return email; } const extractEmailFromAddressString = (address)=>address.trim().replace(/.*<(.*)>/, '$1').trim(); const extractNameFromAddressString = (address)=>address.trim().replace(/(.*)<.*>/, '$1').trim().replaceAll(/^"|"$/g, '').trim().replaceAll(/^'|'$/g, '').trim(); function mapFromAddress(address, defaultFromName, defaultFromAddress) { if (!address) return { email: defaultFromAddress, name: defaultFromName }; if (typeof address === 'string') return { email: extractEmailFromAddressString(address), name: extractNameFromAddressString(address) === address ? undefined : extractNameFromAddressString(address) }; return { email: extractEmailFromAddressString(address.address), name: address.name === address.address ? undefined : address.name }; } function mapAddresses(addresses) { if (!addresses) return []; if (typeof addresses === 'string') return [ { email: extractEmailFromAddressString(addresses), name: extractNameFromAddressString(addresses) === addresses ? undefined : extractNameFromAddressString(addresses) } ]; if (Array.isArray(addresses)) return addresses.map((address)=>({ email: typeof address === 'string' ? extractEmailFromAddressString(address) : extractEmailFromAddressString(address.address), name: typeof address === 'string' ? extractNameFromAddressString(address) === address ? undefined : extractNameFromAddressString(address) : address.name === address.address ? undefined : address.name })); return [ { email: extractEmailFromAddressString(addresses.address), name: addresses.name === addresses.address ? undefined : addresses.name } ]; } function mapAttachments(attachments) { if (!attachments) return undefined; return attachments.map((attachment)=>{ if (!attachment.filename || !attachment.content) throw new APIError('Attachment is missing filename or content', 400); if (typeof attachment.content === 'string') return { content: Buffer.from(attachment.content), filename: attachment.filename }; if (attachment.content instanceof Buffer) return { content: attachment.content, filename: attachment.filename }; throw new APIError('Attachment content must be a string or a buffer', 400); }); } //# sourceMappingURL=index.js.map