SendGrid’s SMTP API allows developers to specify custom handling instructions for e-mail. This is accomplished through a header, X-SMTPAPI, that is inserted into the message. The header is a JSON encoded list of instructions and options for that email. An example header looks like this:

1
2
3
{
  "category": "newuser"
}

In this case, the header is telling the processing routine to assign this email the category of “newuser”.

The X-SMTPAPI Header

The X-SMTPAPI header is a JSON-encoded associative array consisting of several sections, below are examples of JSON strings using each section. This header can be added to any SMTP message sent to SendGrid and the instructions in the header will be interpreted and applied to that message’s transacation.

To: An array of addresses to send the message to, optionally including the display name.

1
2
3
4
5
6
{
  "to": [
    "<ben@example.com>",
    "Joe Smith <joe@example.com>"
  ]
}

Substitution: An associative array of substitution tags, where each tag is associated with a list of replacement text for the tag in the body text. Each Substitution value corresponds to an email in the “To” section of the JSON string.

1
2
3
4
5
6
7
8
9
10
11
12
{
  "sub": {
    "%name%": [
      "Ben",
      "Joe"
    ],
    "%role%": [
      "%sellerSection%",
      "%buyerSection%"
    ]
  }
}

Section: Sections can be used to simplify substitution values that are common to many recipients. This is an associative array of sections that can be used in substitution values.

1
2
3
4
5
6
{
  "section": {
    "%sellerSection%": "Seller information for: %name%",
    "%buyerSection%": "Buyer information for: %name%"
  }
}

Category: Associates the category of email this should be logged as. You may insert up to 10 categories as an array, these categories are not predefined.

1
2
3
4
5
6
{
  "category": [
    "category1",
    "category2"
  ]
}

Unique Arguments: An associative array of arguments and their values to be applied to all emails sent in this SMTP API transaction.

1
2
3
4
5
6
{
  "unique_args": {
    "orderNumber": "12345",
    "eventID": "6789"
  }
}

Apps: An associative array of filters and their settings, used to override filter settings already setup for your account. Settings are an associative array of the setting names and their values.

1
2
3
4
5
6
7
8
9
10
11
{
  "filters": {
    "footer": {
      "settings":
        {
          "enabled": 1,
          "text/plain": "Thank you for your business"
        }
    }
  }
}
All of the above examples can then be combined into one larger JSON string placed in a header named X-SMTPAPI, and would look like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
{
  "to": [
    "ben@sendgrid.com",
    "joe@sendgrid.com"
  ],
  "sub": {
    "%name%": [
      "Ben",
      "Joe"
    ],
    "%role%": [
      "%sellerSection%",
      "%buyerSection%"
    ]
  },
  "section": {
    "%sellerSection%": "Seller information for: %name%",
    "%buyerSection%": "Buyer information for: %name%"
  },
  "category": "Orders",
  "unique_args": {
    "orderNumber": "12345",
    "eventID": "6789"
  },
  "filters": {
    "footer": {
      "settings": {
        "enabled": 1,
        "text/plain": "Thank you for your business"
      }
    }
  }
}

The above example is formatted for readability. Headers must be wrapped to keep the line length under 72. By RFC 821 no line can be longer than 1,000, so if you are going to generate this string yourself it is a good idea to make sure that you wrap it.

Here is a full example of generating the above JSON header in a Perl script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/usr/bin/perl
use strict;
use JSON;

my $header = { to => ['ben@sendgrid.com', 'joe@sendgrid.com],
sub => { '%name%' => [ 'Ben', 'Joe' ], '%role%' =>; [ 'sellerSection', 'buyerSection' ] },
section => { '%sellerSection%' =>; 'Seller information for: %name%', '%buyerSection%' => 'Buyer information for: %name%' },
category => 'Orders',
unique_args => { 'orderNumber' => '12345', 'eventID' => '6789' },
filters => { 'footer' => {'settings' => {'text/plain' => "Thank you for your business"}}}};

my $json = JSON->new;
$json->space_before(1);
$json->space_after(1);
my $js = $json->encode($header);
# This regex breaks the string up at whitespaces to keep the line length short
$js =~ s/(.{1,72})(\s)/$1\n   /g;
my $hdr = "X-SMTPAPI: $js";
print "$hdr\n";

Requirements and Limitations

While there is a hard limit of 10,000 addresses that can be sent to in a multiple recipient e-mail, it is best to split up large jobs at around 1,000 recipients, as this will better allow for the processing load to be distributed. Further, if you have a large number of additional substitions or sections in the headers, it is best to split the send into even smaller groups.

When setting filters via SMTPAPI, all filter names and setting names must be lowercase.

If you use the multiple recipient functionality of the API, you must not send to multiple recipients with the SMTP protocol as well. Doing so can cause duplicates of the message to be sent.

Ensure that the header is limited to a maximum total line length of 1,000 characters. Failure to do this can cause intermediate MTA’s to split the header for you on non-space boundaries, which will cause spaces to be inserted in the final resulting e-mail. In addition, if your e-mail is going through another MTA before reaching SendGrid, it is likely to have an even lower setting for maximum header length and may truncate the header.

When using the API, if our system encounters a parsing error, the message will be bounced to the address specified in the MAIL FROM portion of the SMTP session. The MAIL FROM address is re-written when we send e-mail out for final delivery, so it is safe to set this to an address that can receive the bounces so that you will be alerted on errors.

For substitution tags, it is best to avoid characters that have special meaning in html, such as <,>, and &. These might end up encoded and will not be properly substituted.