Stefan Holm Olsen

Tagging SendGrid mails in Episerver DXC

As part of the Episerver DXC subscriptions we also get a SendGrid account. You can use it as a simple SMTP proxy or you can choose to actively exploit all the nice features they provide.

If you log in to the SendGrid account and look at the activity logs, you will see that it is a chronological log stream, where emails are listed equally. This can be a problem, because that single account will usually be shared by the production, preproduction and integration sites. So, it is mixing up live emails with test emails.

Luckily, SendGrid supports adding tags (or categories, as they call it) to each individual email. By exploiting that feature, we can apply different filters when exploring the activity log. This in turn makes both QA and troubleshooting much easier.

Which tags to put?

I cannot tell you exactly which tags you need to add to your outgoing emails. But here are a few ideas I have had great success with.

Environment

For me, this really is a no-brainer. When you use a single SendGrid account for sending emails from production, preproduction and integration sites, you really need (and wish) to be able to filter the outgoing email logs by environment.

Do this before you are asked to check if a certain email was sent in a certain environment. Otherwise you risk having to find the needle in the haystack.

Email type

Imagine a scenario where a user did not receive an order confirmation email as expected. So, we are tasked with figuring out if it was even sent in the first place. We will start by searching by the user’s email address and look for the email by its subject.

But now you are asked to find all who received order confirmation emails within a date range, to be able to correlate with order listings from Episerver Commerce.

In this case looking up and going through all emails by email address is a very slow procedure. Instead we could filter by email type (and environment) and extract a list to a CSV file. Then an Excel magician can probably do some correlation magic to find the missing emails.

Of course, this requires that we add an "email type" tag on each email when sending. So, you may consider doing that.

Language

This is just another tag which, like email type, is mostly usable for narrowing in on emails. This might also be usable for some custom reporting, but probably not for much else. But it is nice anyway.

Technical solution

In the following sample class, you will see how I add a special mail header ("X-SMTPAPI") to the MailMessage object. When SendGrid receives this email, it will examine the header, act accordingly and then remove it from the final outgoing email.

See what else you can add to the header at SendGrid’s documentation page.

public class SmtpMailSender
{
    private readonly DxcApplicationContext _dxcApplicationContext;
 
    public SmtpMailSender(DxcApplicationContext dxcApplicationContext)
    {
        _dxcApplicationContext = dxcApplicationContext;
    }
 
    public async Task SendMail()
    {
        var message = new MailMessage
        {
            Subject = "Test subject",
            Body = "Test body",
            From = new MailAddress("username@domain.tld", "Test sender")
            // ... Put your other properties here.
        };
 
        message.Headers.Add("X-SMTPAPI", GetSmtpApiHeader());
 
        using (SmtpClient smtpClient = new SmtpClient())
        {
            await smtpClient.SendMailAsync(message);
        }
    }
 
    private string GetSmtpApiHeader()
    {
        string environment = _dxcApplicationContext.CurrentEnvironment.ToString();
 
        // ... Put other properties here (if needed).
        object apiHeaderContent = new { category = new[] { environment } };
        string json = JsonConvert.SerializeObject(apiHeaderContent, Formatting.None);
 
        return json;
    }
}

The following is another sample class, showing how to add the environment tag when sending an email based on a SendGrid transactional template.

public class TemplateMailSender
{
    private readonly DxcApplicationContext _dxcApplicationContext;
    private readonly ISendGridClient _sendGridClient;
 
    public TemplateMailSender(
        DxcApplicationContext dxcApplicationContext)
    {
        _dxcApplicationContext = dxcApplicationContext;
        _sendGridClient= new SendGridClient("TestApiKey");
    }
 
    public async Task SendMail()
    {
        string environment = _dxcApplicationContext.CurrentEnvironment.ToString();
 
        var message = new SendGridMessage();
        message.From = new EmailAddress("username@domain.tld", "Test sender");
        message.TemplateId = "TestTemplateId";
        message.Categories = new List(1) { environment };
 
        Response response = await _sendGridClient.SendEmailAsync(message)
            .ConfigureAwait(false);
    }
}