Receiving emails using Sendgrid Inbound Parse and C# WebAPI2

I had a surprising amount of difficulty getting my WebAPI2 application to receive emails using the SendGrid Inbound Parse feature. So in an effort to prevent others from falling in to the same trap as I did, I decided to make an empty application, and walk through the functionality of my post method so you too can achieve greatness.

In the end, the tool that really save me was Runscope, an API relay system that will layout exactly what is being send from one HTTP client to another. After lots of head banging, I realized the underlying issue was SendGrid was Posting using multipart/form-data as the content type, which WebAPI2 doesn’t seem to understand out of the box (or at least I couldn’t get it to understand).

Let’s get started.

Preliminary steps

  • If you do not already have one, head over to SendGrid and set up a free email account (I’ve used several different email systems, and I find SendGrid to be the most versatile, though maybe lacking on downloadable samples in C#)
  • You need to create a WebAPI2 project, and install Microsoft ASP.NET Cross-Origin Support (since the Post request will be coming from a completely different address then where you API is hosted).

So now that the initial steps are taken care of, you should be looking at this

EmptyProject

 

Create SendGrid Inbound Parse C# class Model

You can view the data model coming from SendGrid in their inbound parse documentation. Here is what you should be expecting

InboundParseModel

So, I created a model to reflect these data points

namespace CSharpSendGrid.Models
{
    public class EmailModel
    {
        public string headers { get; set; }
        public string dkim { get; set; }
        public string to { get; set; }
        public string html { get; set; }
        public string from { get; set; }
        public string text { get; set; }
        public string sender_ip { get; set; }
        public string SPF { get; set; }
        public string attachments { get; set; }
        public string subject { get; set; }
        public string envelope { get; set; }
        public string charsets { get; set; }
    }
}

Create SendGrid Inbound Parse C# WebAPI2 Method

Next we need to create an HTTP controller to accept the POST request coming from SendGrid. You’ll see in the picture below, I’ve enabled CORS from all domains

namespace CSharpSendGrid.Controllers
{
    public class InboundParseController : ApiController
    {
        [HttpPost]
        // POST api/<controller>
        [EnableCors(origins: "*", headers: "*", methods: "*")]
        public async Task<HttpResponseMessage> Test()
        {
            try
            {
                string root = HttpContext.Current.Server.MapPath("~/App_Data");
                var provider = new MultipartFormDataStreamProvider(root);

                StringBuilder sb = new StringBuilder(); // Holds the response body

                // Read the form data and return an async task.
                await Request.Content.ReadAsMultipartAsync(provider);

                //Bind to incoming email model
                Models.EmailModel _em = new Models.EmailModel
                {
                    to = provider.FormData.GetValues("to").SingleOrDefault(),
                    from = provider.FormData.GetValues("from").SingleOrDefault(),
                    subject = provider.FormData.GetValues("subject").SingleOrDefault(),
                    html = provider.FormData.GetValues("html").SingleOrDefault(),
                    sender_ip = provider.FormData.GetValues("sender_ip").SingleOrDefault(),
                    headers = provider.FormData.GetValues("headers").SingleOrDefault(),
                    dkim = provider.FormData.GetValues("dkim").SingleOrDefault(),
                    text = provider.FormData.GetValues("text").SingleOrDefault(),
                    SPF = provider.FormData.GetValues("spf").SingleOrDefault(),
                    attachments = provider.FormData.GetValues("attachments").SingleOrDefault(),
                    envelope = provider.FormData.GetValues("envelope").SingleOrDefault(),
                    charsets = provider.FormData.GetValues("charsets").SingleOrDefault()
                };
                return new HttpResponseMessage(HttpStatusCode.OK);

            }
            catch
            {
                throw;
            }
        }
    }
}

Configure your domain MX records

In order to receive emails from your domain, you will need to configure an MX record in your DNS setting pointing to mx.sendgrid.net

 

Configure SendGrid Inbound Parse endpoint

Go over to you SendGrid account and update your Inbound Parse endpoint. If you are using RunScope to relay incoming API calls, you’ll need to configure this now as well.

If you are hosting your project locally, remember to open a port in both your router, and Windows Firewall.

Gotcha: I had issues trying to get the SendGrid Inbound Parse to send calls to my API when my API was on another port. To combat this, I forwarded port 80 to my application port on IISExpress (see next gotcha below)

Configure IISExpress is running locally

Here is another ‘gotcha‘ in this project. If you are going to run this application locally through Visual Studio, you will need to update your IISExpress configuration to bind to your machine IP, instead of the default localhost.

Click here to view an article on StackOverflow on how to do this.

Here is another thread: http://stackoverflow.com/questions/4709014/using-custom-domains-with-iis-express

 

Add a break point and test your application!

I added a break point to the return call on my POST method so I can run through the incoming data. After everything is configured, try send an email to your application [xxxxx]@[the-domain-you-specified].com.

After sending the email, you should expect to see the application break point trigger in less than a minute. Now you can confirm you are parsing the incoming data and it is being correctly bound to your model.

 

There you go! You’re ready to receive emails using SendGrid Inbound Parse and WebAPI2.

Check out the sample application on GitHub: https://github.com/AJBubb/SendGridInboundParse

 

Feel free to fork me and add things such as database saving, attachment downloading, and more!

 

Thanks for reading, hope this helps!

AJ Bubb

Altify Software

AJ Bubb

AJ has over a decade of experience leading and managing technical projects. Focused primarily on the .Net stack, AJ has been part of several start ups, and worked with multi-national companies. In his free time, he is a scuba diving instructor, outdoor enthusiast and idea hacker.

More PostsWebsite

Follow Me:
TwitterFacebookLinkedIn