Build Two-Way Email to Text Forwarding with SendGrid and Twilio

March 04, 2020
Written by
Toby Allen
Twilion

After this post was originally published, Zeit rebranded to Vercel. The tutorial is now outdated – our team is evaluating how to update the post.

Lots of businesses want to be able to communicate over SMS with their customers but struggle to integrate this channel with established processes like shared email inboxes. Should you share a phone with the team, or should you opt for an inflexible third-party email to SMS gateway with strict routing rules?

With the power of Twilio SendGrid and Twilio SMS, you have a better option: set up your own two-way forwarding solution to send an email to text message (or a text message to email). 

In this short tutorial, you'll learn how to route messages from a Twilio SMS-capable number to a shared inbox and vice versa. We’ll do this by sending inbound text messages to email using the SendGrid API. Conversely, we'll leverage SendGrid's Inbound Parse functionality to call the Twilio Messaging API. In both cases, we're going to use a small JavaScript function hosted in the Zeit Serverless environment. We chose Zeit for this because it supports receiving multipart/form-data requests, which are required for the Inbound Parse Webhook.

Two-way email to text forwarding tutorial requirements

To follow this tutorial, you'll need the following items:

  • A Twilio account — If you are new to Twilio you can create a trial account with a US $15 trial credit
  • A Twilio SendGrid account — If you are new to Twilio SendGrid, you can create a free account, which allows you to send 100 emails per day forever.
  • A Zeit account — find out more and create one here
  • A GitHub account if you'd like to use the quick deploy option.

How it works

Before we dive into the setup, here is how it works. When an SMS is sent to the Twilio phone number, we receive it and pass it onto the destination email.

Incoming SMS to Email demo

 

Incoiming SMS forwarded to email through SendGrid

If you reply to the email message, we'll send it back to the original sender as an SMS.

Replying to an SMS through email

Alternatively, anyone can SMS by sending an email in the form of <country code><phone number>@<email domain> SendGrid will forward it to our function, which extracts the body and sends it as an SMS to the phone number specified in the email address.

Send SMS to email

This function is triggered by a WebHook from Twilio whenever a message arrives at our destination phone number. The function creates an array to describe the email and uses the body of the inbound text as the email body. We specify the originating email address as <sending phone number>@<email domain> so that you can reply to the email, and it will go back to the same person.

const sgMail = require('@sendgrid/mail');
const MessagingResponse = require('twilio').twiml.MessagingResponse;
module.exports = (req, res) => {
    //Specify API Key for Sendgrid
    sgMail.setApiKey(process.env.SENDGRID_API_KEY);

    //Set from address as <number>@EMAIL_DOMAIN
    const fromAddress = req.body.From.replace("+", "") + `@${process.env.EMAIL_DOMAIN}`;

    //Create Email
    const email = {
        to: process.env.TO_EMAIL_ADDRESS,
        from: fromAddress,
        subject: `New SMS message from: ${req.body.From}`,
        text: req.body.Body,
    };
    
    // Send the email
    sgMail.send(email)
        .then(response => {
            res.status(200).send(response); //Make sure we return correctly.
        })
};

Send email to SMS

This function is slightly more complicated than the above one as SendGrid uses multipart/form-data in its webhook. This means that we need to pass the request through a library called multer, which is designed to handle these requests. We can then extract the phone number and the message body. We then use the Twilio NodeJS Library to send the message off. If there are any errors, we capture these and email them back to the sender.

const util = require('util');
const multer = require('multer');
const addrs = require("email-addresses");
const sgMail = require('@sendgrid/mail');
const twilio = require('twilio');

module.exports = async (req, res) => { 
    const client = twilio(process.env.TWILIO_ACCOUNT_SID,process.env.TWILIO_AUTH_TOKEN);
    await util.promisify(multer().any())(req, res);

    const from = req.body.from;
    const to = req.body.to;
    const subject = req.body.subject;
    const body = req.body.text;

    //Using email-addresses library to extract email details.
    const toAddress = addrs.parseOneAddress(to);
    const toName = toAddress.local;
    const fromAddress = addrs.parseOneAddress(from);
    const fromName = fromAddress.local;

    //Sending SMS with Twilio Client
    client.messages.create({
        to: `+${toName}`,
        from: process.env.TWILIO_PHONE_NUMBER,
        body: `Message from:${fromName}\n${body}`
    }).then(msg => {
        console.log(msg)
        res.status(200).send(msg.sid);
    }).catch(err => {
        //If we get an error when sending the SMS email the error message back to the sender
        sgMail.setApiKey(process.env.SENDGRID_API_KEY);

        // Create Email
        const email = {
            to: fromAddress.address,
            from: toAddress.address,
            subject: `Error Sending SMS to ${toAddress.local}`,
            text: `${err}\n For email from ${fromAddress.address}`,
        };
        //Send Email
        sgResp = sgMail.send(email)
            .then(response => {
                res.status(200).send("Sent Error Email");
            })
            .catch(error => {
                res.status(500);
            });
    });
};

Step 1: Gathering info for the serverless app

Before we can dive into getting the app running, there are a few bits of information that we need:

  • Twilio Account SID and Auth Token, which are available from the account dashboard. (More information is found here).
  • A SendGrid API Key, which you can find here. If you’re unsure how to create an API key check out the documentation
  • An SMS capable Twilio number which you can grab from the Phone Numbers page in the console
  • A dedicated subdomain domain where you can configure MX records— to allow SendGrid to receive emails.
  • A destination email address for inbound emails.

Step 2: Zeit Now setup

There are two ways that you can deploy to Zeit Now. Quick Deploy and from the command line. Quick Deploy is the simplest but requires a GitHub account. Command-line requires more setup but allows you to modify and test the code more easily.

Quick Deploy

To deploy the sample application, you first need to ensure that Zeit and Github are linked. The simplest way to do this is to go to Your Account - Git Integrations on Zeit and follow the prompts to connect. Once connected, click the button below or follow this link.

Deploy to Zeit

This should present a “Create a New Project” page in Zeit, as shown below. To deploy, please fill in the Environment Values that you gathered above.

Git create a new project

After filling in the details and hitting Deploy, you’re eventually presented with a screen like the one below.

Deploy a git project to Zeit

To test that everything is loading up correctly copy on the domains from the screen and browse to https://<domain>/api/index and you should get a “Hello World!”. Now note down the domain for later as we’ll need this in our Twilio and SendGrid setups to configure the “When a Message Comes in” and “Inbound Parse” webhooks.

Command line setup

If you’re choosing to deploy from the command line instead of using the deploy button, then the steps are as follows:

  1. Install the Now CLI following the instructions here

npm i -g now
now login
  1. Clone the GitHub Repository to your computer
git clone https://github.com/tobyallen/email2sms
cd email2sms
  1. Use the “now secrets” to add the environment variables. (More info here).
now secrets add TWILIO_ACCOUNT_SID <Value>
now secrets add TWILIO_AUTH_TOKEN <Value>
now secrets add SENDGRID_API_KEY <Value>
now secrets add EMAIL_DOMAIN <Value>
now secrets add EMAIL_ADDRESS <Value>
now secrets add TWILIO_PHONE_NUMBER <Value>
  1. Deploy by executing the now Command:
now
  1. Copy the deployment address shown.

Step 3: Twilio setup

Configuring the phone number

To make sure inbound text messages are sent as emails, we’ll need to configure our phone number to point to our function. To do this, select your phone number from the Active Numbers page and update the messaging section A Message Comes in to Webhook and paste in

<deployment url>/api/sms2email that is add /api/sms2email to the end of your deployment url in the webhook section as shown below.

Setting a messaging webhook with Twilio

Step 4: SendGrid setup

Receiving email - AKA Inbound Parse

To receive emails, we need to configure an Inbound Parse Webhook. When this is set, SendGrid will parse an email and its attachments and POST it to a URL specified. In our case, we’re going to specify a function URL so we can process the inbound emails. To process inbound emails, we need to specify a hostname dedicated to parsing inbound emails such as parse.<yourdomain>.com and update the MX records for this hostname to point to mx.sendgrid.net. This sounds complicated, but fortunately, the documentation we've provided has you covered. You set the receiving domain to what you picked above and point the destination URL to <deployment url>/api/email2sms

Add an inbound parse webhook with SendGrid

Step 5: Testing SMS and email forwarding

To test out your deployment, first send an SMS to the Twilio phone number you used. In less than a minute, you should receive an email to the email address you specified above. You can reply directly to this email, and shortly after, you should receive an SMS back from the original phone number. You can also send an SMS by emailing <e.164 phone number>@<email domain> where an E.164 number is the country code plus the phone number without any leading zeros.

Troubleshooting

Hopefully, everything works without a hitch. But if there are any problems, head to your Zeit Dashboard, click on the deployment name, and view the logs. Any deployment errors and everything logged to the console should show up here. Additionally, you can check the Twilio Debugger, which shows any problems on the Twilio side with instructions on how to resolve them.

Forward SMS to email (and email to SMS) using Twilio

The solution shown here is a simple two-way link between a shared inbox and a Twilio phone number. You can extend this to support multiple inbox-to-phone-number mappings by leveraging an array or database to map between a Twilio phone number and the email address of choice.

Learn more about what you can do with Twilio’s SMS API

Toby Allen is a Twilio Solutions Architect working with customers large and small in Australia. He helps introduce the world's best Communications Cloud downunder, one CURL request at a time. He is helping companies build great user experiences making sure that they leverage all the contextual information they have at hand. He has been working in real time communications for 15 years from developing video solutions to enterprise to helping carriers deploy globe spanning voice and messaging solutions including more than two years working with communications clouds. He’s active on Twitter @tobyallen and LinkedIn.