Last active
June 20, 2021 06:50
-
-
Save shaneosullivan/993d09a73bd8f5895e7513a49ac8d914 to your computer and use it in GitHub Desktop.
Forward an email with SendGrid and Formidable
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
import fs from "fs"; | |
// You can use "formidable-serverless" if in a serverless environment like | |
// AWS Lamba or Google Cloud Functions | |
import formidable from "formidable"; | |
import sendgridMail from "@sendgrid/mail"; | |
import { AttachmentData } from "@sendgrid/helpers/classes/attachment"; | |
sendgridMail.setApiKey(process.env.SENDGRID_API_KEY); | |
// See https://www.npmjs.com/package/formidable | |
interface FormidableFile { | |
// The size of the uploaded file in bytes. | |
// If the file is still being uploaded (see `'fileBegin'` event), | |
// this property says how many bytes of the file have been written to disk yet. | |
size: number; | |
// The path this file is being written to. You can modify this in the `'fileBegin'` event in | |
// case you are unhappy with the way formidable generates a temporary path for your files. | |
path: string; | |
// The name this file had according to the uploading client. | |
name: string | null; | |
// The mime type of this file, according to the uploading client. | |
type: string | null; | |
// A Date object (or `null`) containing the time this file was last written to. | |
// Mostly here for compatibility with the [W3C File API Draft](http://dev.w3.org/2006/webapi/FileAPI/). | |
lastModifiedDate: Date | null; | |
// If `options.hash` calculation was set, you can read the hex digest out of this var. | |
hash: string | "sha1" | "md5" | "sha256" | null; | |
} | |
// Hook this up to your inbound API however you like, e.g. | |
// using Express | |
function handleRequest(req, res) { | |
const form = new formidable.IncomingForm(); | |
form.uploadDir = "/tmp/"; | |
form.keepExtensions = true; | |
form.type = "multipart"; | |
form.multiples = false; | |
form.parse(req, async (_err: any, fields, files) => { | |
handleFormidableResult(fields, files).then(() => { | |
// Send whatever you want | |
res.status(200); | |
res.json({ success: true }); | |
res.end(); | |
}); | |
}); | |
} | |
async function handleFormidableResult(fields, files) { | |
const { to, subject, from, html } = fields; | |
const fileKeys = Object.keys(files); | |
let attachments: Array<AttachmentData> = null; | |
let cleanupPromises = null; | |
if (fileKeys.length > 0) { | |
const filesInfo = fileKeys.map((key) => files[key]) as Array< | |
FormidableFile | |
>; | |
const attachmentPromises = filesInfo.map((fileInfo) => { | |
return new Promise((resolve, reject) => { | |
fs.readFile(fileInfo.path, (err, data) => { | |
if (err) { | |
reject(err); | |
return; | |
} | |
const attachment: AttachmentData = { | |
// Encode the buffer as a base64 encoded string | |
content: data.toString("base64"), | |
filename: fileInfo.name, | |
type: fileInfo.type, | |
disposition: "attachment", | |
contentId: fileInfo.hash, | |
}; | |
resolve(attachment); | |
}); | |
}); | |
}); | |
// Feel free to do better error handling, where if one file fails to | |
// read then you still attach others. Keeping it simple here. | |
attachments = (await Promise.all(attachmentPromises)) as Array< | |
AttachmentData | |
>; | |
// Delete all temp files. | |
cleanupPromises = filesInfo.map((fileInfo) => { | |
return new Promise((resolve, reject) => { | |
fs.unlink(fileInfo.path, () => { | |
resolve(null); | |
}); | |
}); | |
}); | |
} | |
const emailBody = html || fields.text; | |
const message = { | |
from: "no-reply@example.com", | |
to, | |
subject, | |
html: emailBody, | |
envelope: { | |
from: "no-reply@example.com", | |
to, | |
}, | |
attachments, | |
}; | |
try { | |
await sendgridMail.send(message); | |
} catch (err) { | |
console.error("Sending email failed with error", err, " message ", message); | |
} finally { | |
if (cleanupPromises) { | |
await Promise.all(cleanupPromises); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment