We have a Rails app that sends its mail through SendGrid.
SendGrid lets you specify metadata in your mail headers, which you can put to excellent use.
The activity log
SendGrid’s highly useful activity log (docs) lists the last week of sent mail. Not the full mail, but the recipient e-mail address, the time it was sent, and its state (delivered, link in mail was clicked etc) as far as SendGrid can tell.
You can filter the list by e-mail address, which is really handy for debugging and customer support.
But the list doesn’t contain the mail body, or subject, or anything to help you tell which mail is which.
This can be solved with SendGrid metadata and some Action Mailer trickery.
Categories
You can set up to 10 categories as SendGrid metadata on each mail:
1 2 3 4 5 6 7 8 9 10 11 | |
They’re not predefined, so you can use an unlimited number of categories in total.
You can use categories to filter your statistics. Categories are also displayed in the activity log, which may give you an idea of what we’ll do in a bit.
Unique arguments
You can also add any keys and values you like as so-called unique arguments:
1 2 3 4 5 6 | |
They’re also shown in the activity log.
Note that the values will be turned into strings. If a value is a Ruby array, you’ll just see “Array” in SendGrid, so if you want them, do:
1 2 3 4 5 | |
Setting metadata from mail automatically
So how do we automatically store the mailer and action (and some additional goodies) in the SendGrid metadata?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | |
Any mailer that inherits from ApplicationMailer will now get the following metadata:
- A category with the name of the mailer, e.g. “MyMailer”
- A category with the mailer and action, e.g. “MyMailer#hello”
- A unique argument with the Rails environment, e.g. “production”
- A unique argument with the arguments passed into the mailer as a hash from argument name to value, like “{:foo_id=>123, :bar_id=>456}”
The mailer arguments will be rather a lot of text if you pass in full Active Record instances. If you use resque_mailer like we do, you will usually be passing only record ids, so it will be more compact.
Instead of this:

The log will show this:

Having this data is really handy, and I was pretty happy with this implementation. Sure beats looking at the call chain :)