Saturday, November 14, 2020

Inbound Email Handling with Google Cloud Functions

Summary

This post covers the intake of emails w/attachments into Google Cloud Functions (GCF).  The code here covers storing those attachments into a Cloud bucket.

There is no native SMTP trigger for GCF, so a 3rd party needs to be used to convert the email to an HTTP POST that can subsequently trigger a GCF.  In this case, I used CloudMailin.  They have a nice interface and are developer-friendly.  The GCF then needs to process the multipart form data and write the file attachments to Cloud Storage.

Part 1:  Inbound Email Handling with Google Cloud Functions

Architecture



Code Snippet - GCF Trigger

exports.uploadRma = (req, res) => {
	if (req.method === 'POST') {
		if (req.query.key === process.env.API_KEY) {  
			upload(req)
			.then(() => {
				res.status(200).send('');

Code Snippet - Upload function

The Busboy module is leveraged to do the heavy lifting of parsing the multi-part form.  Each file is written to a UUID "folder" in Cloud Storage.  Those writes are stored in a Promise array that is resolved when all the attachments of the form have been parsed.

		const busboy = new Busboy({headers: req.headers});
		const writes = [];
		const folder = uuidv4() + '/'; 

		busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {
			console.log(`File received: ${filename}`);
			writes.push(save(folder + filename, file));
		});

		busboy.on('finish', async () => {
			console.log('Form parsed');
			await Promise.all(writes);
			resolve();
		});

		busboy.end(req.rawBody);

Code Snippet - Save function

A read stream for the file attachment is piped to a write stream to Cloud Storage.
function save(name, file) {	
	return new Promise((resolve, reject) => {
		file.pipe(bucket.file(name).createWriteStream())
		.on('error', reject)
		.on('finish', resolve);
	});
}

Results

Original Email


Cloud Logs


Cloud Storage




Source


Copyright ©1993-2024 Joey E Whelan, All rights reserved.