Sending email from windows store apps using SendGrid Web Api and HTTP Client

One of the things you will notice when working on windows store applications is that there isn’t any api’s within windows runtime or .NET for Windows Store apps for sending emails. You can of course have a hyperlink button with navigateUri set to mailto:somebody@somecompany.com for ex. to send emails using the mail client installed. What if you want to attach a file or generate email in a specific format or have a cool UI in your app for allowing users to contact you as app developer? In this post I will walk through how I used SendGrid and HTTP client to accomplish just that. One thing I want to point out that the C# SDK from SendGrid cannot be used in windows store apps due to references to API’s and libraries that aren’t simply supported in windows store apps. This is the primary reason why I chose to use HTTP client and roll my own service that Views and ViewModels within my app can consume.

If you are not familiar with SendGrid Web Api check out this awesome documentation from SendGrid team https://sendgrid.com/docs/API_Reference/Web_API/index.html

If you have never used SendGrid before you can check out more info at their site https://sendgrid.com, Its super easy to sign up. Best part is SendGrid is also available for use within your cloud applications in Windows Azure. Really a great example of an excellent online service, cloud enabled and you can use it from anywhere, web, devices, etc.

Define a new class called EmailMessage in your windows store project as shown below, basically this class will be used as a data object when sending emails from your app using email service that we will define later.

 internal class EmailMessage
 {
     public string From { get; set; }
     public string FromEmail { get; set; }
     public string To { get; set; }
     public string ToEmail { get; set; }
     public string Subject { get; set; }
     public string Body { get; set; }
     public IReadOnlyList<StorageFile> Attachments { get; set; }
 }

Next we define an interface called IEmailService, see below

 interface IEmailService
 {
     string ApiUser { get; }
     string ApiKey { get; }
  
     Task<String> SendEmail(EmailMessage message);
 }

Now we’ll define the EmailService class which will implement the IEmailService interface. In this class I defined constants to hold the SendGrid web api parameter names.

 

In the constructor I set the ApiUser and ApiKey property by reading values stored in Resource file. You probably should store these in a more secure location as one could easily reflect the assembly and see the values from Resource files.

SendEmail Implementation

The implementation for SendEmail method is quite straight forward, see the code below. Below Implementation also supports sending attachments, EmailMessage class has a property which is a read only collection of StorageFiles, this can be set from calling method if out going email message requires file attachments.

 public async Task<string> SendEmail(EmailMessage message)
 {
    HttpClient httpClient = null;
    string responseData = string.Empty;
    try
    {
        using (var postData = new MultipartFormDataContent())
        {
            var subjectContent = new StringContent(message.Subject);
            subjectContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
            {
                Name = SubjectParam
            };
            postData.Add(subjectContent);
            var bodyContent = new StringContent(message.Body);
            bodyContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
            {
                Name = HtmlParam
            };
            postData.Add(bodyContent);
            //setup api key and api user param
            var apiUserContent = new StringContent(ApiUser);
            apiUserContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
            {
                Name = ApiUserParam
            };
            postData.Add(apiUserContent);
            var apiKeyContent = new StringContent(ApiKey);
            apiKeyContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
            {
                Name = ApiKeyParam
            };
            postData.Add(apiKeyContent);
            var fromNameContent = new StringContent(message.From);
            fromNameContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
            {
                Name = FromNameParam
            };
            postData.Add(fromNameContent);
            var fromContent = new StringContent(message.FromEmail);
            fromContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
            {
                Name = From
            };
            postData.Add(fromContent);
            StringContent toContent = new StringContent(message.ToEmail);
            toContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
            {
                Name = ToParam
            };
            postData.Add(toContent);
            var toNameContent = new StringContent(message.To);
            toNameContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
            {
                Name = ToNameParam
            };
            postData.Add(toNameContent);
            if (message.Attachments.Count() > 0)
            {
                foreach (var attachment in message.Attachments)
                {
                    Stream fs = await attachment.OpenStreamForReadAsync();
                    postData.Add(AddFile(fs, FilesParam, attachment.Name));
                }
            }
            string fullUrl = string.Format("https://{0}{1}", SendGridHost, Uri);
            httpClient = new HttpClient();
            HttpResponseMessage response = await httpClient.PostAsync(new Uri(fullUrl), postData);
            using (HttpContent content = response.Content)
            {
                responseData = await content.ReadAsStringAsync();
            }
            if (response.StatusCode != System.Net.HttpStatusCode.OK)
                throw new Exception(responseData);
        }
        return responseData;
    }
    finally
    {
        if (httpClient != null)
            ((IDisposable)httpClient).Dispose();
    }
 }

Handling File Attachments

Helper method for file attachments for emails.

 private StreamContent AddFile(Stream stream, string name, string fileName)
 {
     var fileContent = new StreamContent(stream);
     fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
     {
         Name = string.Format("{0}[{1}]", name, fileName),
         FileName = fileName
     };
     fileContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
     return fileContent;
 }

 

Sending Email

Here is an example of sending email using the service from your windows store app, I’m using ServiceLocator to get an instance of email service.

 IEmailService emailService = ServiceLocator.Current.GetInstance<IEmailService>();
 await emailService.SendEmail(new EmailMessage()
 {
     To = "Someone",
     ToEmail = "someone@somecompany.com",
     From = "",
     FromEmail = "",
     Body = "Sending Email from Windows Store apps",
     Subject = "Sending Email from Windows Store apps",
     Attachments = new ReadOnlyCollection<StorageFile>(attachments)
 });

I will be publishing a Sample to MSDN code sample site and will update this post with links

Hope this helps

Cheers,

</Ram>