Build 2-Way Conversational Email Experiences Using SendGrid Inbound Parse

September 22, 2025
Written by
Reviewed by
Paul Kamp
Twilion

Agentic Email with Twilio SendGrid? Yes, Please! Part 1: Inbound Parse with Signature Verification

Voice AI “Agentic” Applications have been getting all of the attention lately, and rightfully so. Generative AI (GenAI) has unlocked new capabilities that can be delivered very effectively over voice. (Be sure to check out Twilio’s ConversationRelay! )

But what about Agentic Email?

Email is a very widely used channel – over 360 billion emails were sent in 2024 – and it isn’t going anywhere. It does not take much to realize and embrace the notion that email, as an ubiquitous low-friction channel, is a terrific vehicle for delivering GenAI applications. And at Twilio, SendGrid’s Inbound Parse feature can help you design the two-way email experiences you want to build in the era of AI.

A GenAI solution for email should be able to (1) receive emails to your desired email domain, (2) securely receive and store inbound emails, (3) Summarize, categorize and route emails for additional processing, and (4) analyze the content and trigger additional events. And, don’t worry – that’s what this solution does (in two parts):

Flowchart showing steps in processing inbound emails
Flowchart showing steps in processing inbound emails
  1. Inbound Parse with Signature Verification
  2. Process Inbound Emails with Generative AI

In Part 1, we will deploy a Cloudformation Stack that will spin up an API Gateway endpoint, S3 buckets, Lambda functions, and an SNS topic. In addition, we configure an Inbound Parse webhook and secure it with a Signature Verification policy. A second stack will establish a simple event handler that shows how you could trigger events to run other systems to process inbound emails.

Part 1 may be all you need if you’re looking to receive emails, but some of you will want to follow Part 2 as well. In Part 2, we enhance those events triggered at the end of Part 1 using Generative AI using models on AWS Bedrock. Events (inbound emails) are first summarized and categorized using GenAI and are then routed for additional processing depending on how they were categorized.

Let’s get started!

Architecture of a two-way email application using SendGrid Inbound Parse

Here is the architecture you’ll be building in this tutorial:

Diagram of Twilio email processing workflow involving inbound parsing, API gateway, SQS, processing, and SNS.

Let’s explore these sections in more detail, starting from the top…

  1. Inbound Emails: Emails from your users are sent to a domain that you have configured in SendGrid to receive inbound mails.
  2. Inbound Parse: Twilio SendGrid takes those emails and forwards the emails individually via a POST to the endpoint that you configured when setting up Inbound Parse. In addition, SendGrid adds a signature header so that you can verify that these emails are from SendGrid and the domain you configured. (This is key functionality to ensure that the emails you receive to your endpoint are coming from Twilio SendGrid)
  3. API Gateway: Now the emails arrive at your AWS account where you have deployed the resources in this blog post. API Gateway provides the endpoint and delivers the payload to a Lambda function.
  4. Initial Lambda: The first Lambda function checks the security header to make sure the email is from your SendGrid account. It then stores the email in its raw format in an S3 bucket.
  5. Queue: When a new object is created in the S3 bucket, an event is triggered that adds a message to an SQS queue. Adding this queue allows you to manage spikes in traffic.
  6. Parse Lambda: Another Lambda function takes the messages from the queue and parses the content, storing primary data in a JSON file saved to a different S3 bucket. It also parses any attachments and saves those separately in S3 as well.
  7. Publish for Processing: Lastly, this lambda publishes to an SNS topic which allows additional systems to subscribe to receive these events and process these emails further.

How should you think about email experiences with Generative AI?

Email is a channel that allows for deep user input in the form of written text and attachments. If the immediacy of the experience you are building isn’t as big of a concern, you should consider building over email.

Providing experiences to handle support, sales, general inquiries, and account issues are just a few places where interactive email could be very effective and compelling. While not synchronous like voice or as fast as chat, email powered by Twilio SendGrid can be received and delivered very quickly. Depending on how you choose to process inbound messages (and for which processes you have a human in the loop), it might be reasonable to reply to customer emails with intelligent and actionable responses in a matter of seconds or minutes.

Prerequisites

This is not a beginner level build! You should have some knowledge of SendGrid and email, AWS, serverless computing, and programming before continuing.

This project is a starter kit for an AWS serverless solution for securely processing inbound emails from SendGrid's Inbound Parse webhook. This solution is not production ready. You will need to customize your enterprise’s business logic, add production-ready features, add guardrails to the app, and integrate into existing systems before deploying to production.

Clone the repo and build the app

As I said before, this is not a beginner project. However, there is a lot of functionality here and you should be able to kickstart your project to build a production-ready inbound email application.

If you’ve completed the prerequisites, the README files explain everything you need to get part 1 up and running.

Start with the high level README file where you will follow instructions to clone the repo and configure your AWS profile and a global configuration file.

Move to the README to proceed with the build:

🚀 README file for Part 1

Run and test the application

Finished deploying? Nice work! Let’s send some test emails to explore how this works…

Send an email

First, you’ll need to send an email to the domain you configured for Inbound Parse. To match my example, you can ask about dog products. Importantly, you should also add an attachment (a photo, in my case) to test that attachments are parsed as well. Here’s how I tested:

Using an email address for the domain I configured for Inbound Parse, I asked about products for my dog, Mabel: I would like to purchase one of your products for my dog. Can you make some suggestions? I attached a photo of my dog.

Whether you’re copying my example or making your own, send the email. If it doesn’t bounce, move onto the next step.

Email composition with a photo of a black and white dog sitting on a beach attached

Raw email in the S3 Bucket

The email gets routed to SendGrid, and SendGrid then POSTs it to your Inbound Parse endpoint. There, API Gateway passes it to a Lambda function which checks the security header and puts the raw (b64) content into an S3 bucket.

Go to this bucket in your AWS Console to view this file to ensure you received your test email. If you see a new Object in the bucket with the .b64 extension, it worked! Move on to the next step.

Screenshot of Amazon S3 interface showing an object with its details and options for actions taken on September 10, 2025.

Find the parsed email in the S3 Bucket

Creating the object from the raw email in the S3 bucket (from step 2 above) fires an event which triggers another lambda that parses the contents of the email. This event is triggered because we set up an onCreateObject event on the S3 bucket and the Lambda function is configured to consume these events. Now, you can verify that the parsing function was triggered.

Go to the twilio-sendgrid-inbound-parse- S3 bucket and you should see a new folder that contains the parsed contents of the email you sent. Here are the files produced for my email:

Amazon S3 interface showing details of objects within a specific bucket, including timestamps and JSON files.

The email.json file contains everything but the attachments. If you open that file, you will notice all of the properties broken into a JSON object and ready to be consumed by the next system. In Part 2, the JSON object will be sent to another Lambda function where the content will be summarized and categorized by GenAI (via AWS Bedrock) and then processed further depending on the category it receives.

{
"messageId": "4412b523-3121-45fa-8a66-35772d757b53",
"messageTimeStamp": 1757570217436,
"snsObject": {
"messageId": "4412b523-3121-45fa-8a66-35772d757b53",
"messageTimeStamp": 1757570217436,
"to": "dan@some-inbound-email.domain.com",
"from": "\"Dan Bartlett\" <some-user@some-outbound-email.domain.com>",
"subject": "Blog Email",
"attachments": 1,
"contentTypes": [
"text/plain",
"text/html"
]
},
"charsets": "{\"to\":\"UTF-8\",\"from\":\"UTF-8\",\"subject\":\"UTF-8\"}",
"sender_ip": "148.163.149.14",
"to": "dan@some-inbound-email.domain.com",
"from": "Dan Bartlett <dbartlett@some-outbound-email.domain.com>",
"subject": "Blog Email",
"envelope": "{\"to\":[\"dan@some-inbound-email.domain.com\"],\"from\":\"some-user@some-outbound-email.domain.com\"}",
"dkim": "{@twilio.com : pass}",
"spf": "pass",
"emailContent": {
"subject": "Blog Email",
"from": "\"Dan Bartlett\" <some-user@some-outbound-email.domain.com>",
"to": "dan@some-inbound-email.domain.com",
"date": "2025-09-11T05:56:39.000Z",
"messageId": "<CAFvx8W7iXHm_DbeNZdOWso3utmuOaeWnsz0XYpHuQYsM_rLUyA@mail.gmail.com>",
"text/plain": "I would like to purchase one of your products for my dog. Can you make some\nsuggestions? I attached a photo of my dog.\n\n[image: mabel-beach.png]\n",
"text/html": "<div dir=\"ltr\"><div><span style=\"font-family:verdana,sans-serif\">I would like to purchase one of your products for my dog. Can you make some suggestions? I attached a photo of my dog.</span></div><div><span style=\"font-family:verdana,sans-serif\"><br></span></div><div><p><i>[image: mabel-beach.png]</i></p><br></div><div><div dir=\"ltr\" class=\"gmail_signature\" data-smartmail=\"gmail_signature\"><div dir=\"ltr\"><div style=\"margin:0px;padding:0px;color:rgb(13,18,43);font-family:-apple-system,system-ui,&quot;Helvetica Neue&quot;,sans-serif;font-size:14px\"></div></div></div></div></div>\n"
},
"emailAttachments": [
{
"filename": "mabel-beach.png",
"type": "image/png",
"key": "4412b523-3121-45fa-8a66-35772d757b53/email-attachments/mabel-beach.png",
"size": 931554,
"contentId": "<ii_mfezwq0o0>",
"summary": "A dark-colored dog with a red collar sits attentively on a sandy beach with ocean waves in the background."
}
]
}

Any attachments are saved to a separate folder, email-attachments. If you sent an email similar to mine, you should see a photo inside:

Interface of Amazon S3 Storage displaying an uploaded file named mabel-beach.png.

And of course the attachments are able to be processed as well:

A happy dog with a collar stands on a sandy beach with the ocean in the background.

SNS Message Published

Finally, an SNS message is published for downstream processing. The messageId is the key to accessing all of the content saved in the S3 bucket.

The payload for the SNS message will look something like this:

"messageId": "4453554-3244-fdfa-8a66-3jdjhd8b7d752",
	"messageTimeStamp": 1757570217436,
	"to": "dan@some-email-domain.com",
	"from": "\"Dan Bartlett\" <someemail@somedomain.com>",
	"subject": "Blog Email",
	"attachments" : 1
}

What else is in there? A preview of Part 2

Eagle-eyed readers may have noticed a file called llm-response.json. In Part 2 we trigger a process to summarize and categorize the contents of the email, route the email to a specialized handler based on the category, and then trigger next actions – like sending a reply email!

Continue to Part 2 to build out that functionality.

Limitations

AWS API Gateway has a hard limit of 10 MB for REST payloads. SendGrid allows for payloads up to 30 MB. This means that emails with large attachments over the API Gateway limit will be rejected.

If your use case is not expecting attachments or not expecting large attachments, then this architecture should be a great starting point.

If you need to handle larger email attachments, then you would need to build an alternative endpoint. For example, an Application Load Balancer (ALB) could replace API Gateway in the architecture. The ALB would be backed by a service that streams the payload to an S3 bucket. The S3 bucket would have an onCreate trigger that kicks off the Lambda to begin the processing.

It would be a good idea to turn on logging for the API Gateway to keep track of any requests that are rejected for being larger than the size limit.

Conclusion

You now have the foundation in place to securely receive Inbound Emails sent to your chosen email domain, parse those emails, and then triggering additional systems for more processing. If that’s all you needed to build, you can find more information on Inbound Parse in the SendGrid Docs, and more information on Lambda in AWS’s Docs.

If you’re continuing on, in Part 2 of this solution, we add that “more processing” and show how your organization could build a GenAI Email application! Hope to see you there.

Continue to part II.


Dan Bartlett has been building web applications since the first dotcom wave. The core principles from those days remain the same but these days you can build cooler things faster. He can be reached at dbartlett [at] twilio.com.