Putting webhooks to work

Wouldn’t it be great to live in a world where instead of having to go out and grab the data you need using an API, you could have that data sent to you? Instead of polling the Postmark API, does receiving real-time notifications that are pushed to you sound like a dream? Postmark has this functionality now, in the form of webhooks. What a time to be alive!

Postmark provides webhooks for bounces, inbound messages, and open tracking events in the form of HTTP POSTs in well formatted JSON to the URL(s) you specify. Using these webhooks you can receive notifications and data as the triggering events occur, without having to make any calls to our API.

Webhook applications #

There are many ways you can make use of our webhooks. The following are some examples of how they can be used to help you get the most out of the Postmark platform.

Bounce & spam complaint notifications #

Using our Bounce webhook you can receive POSTs to your webhook URL for bounces every time a bounce event occurs. The JSON format for bounce and spam complaint notifications is:

{
  "ID": 42,
  "Type": "HardBounce",
  "TypeCode": 1,
  "Name": "Hard bounce",
  "Tag": "Test",
  "MessageID": "883953f4-6105-42a2-a16a-77a8eac79483",
  "Description": "The server was unable to deliver your message (ex: unknown user, mailbox not found).",
  "Details": "Test bounce details",
  "Email": "john@example.com",
  "BouncedAt": "2014-08-01T13:28:10.2735393-04:00",
  "DumpAvailable": true,
  "Inactive": true,
  "CanActivate": true,
  "Subject": "Test subject"
}

Using the received JSON, you can quickly locate the email that triggered the notification (using the MessageID JSON key), check if the recipient can be reactivated (using the CanActivate key), and find out additional details around why the email bounced (using the Description and Details keys). What data interests you and how you use it is depends on your use case, but Postmark can help you get what you need.

One popular application of the bounce webhook is to send an email alert every time you receive a bounce or spam complaint. Once a new bounce notification arrives at your bounce webhook URL, you can construct an email with the data to send to an email address or addresses of parties who want to be aware of bounces and spam complaints using our Email API or SMTP

The bounce notification can also be used to mark a user or email address in your application as bouncing and provide your users with a way to reactivate the address manually using our Bounce API. Want to only receive an email if the bounce is a hard bounce? Check the Type key for a value of “HardBounce”. Only concerned about new spam complaints? Check the same key for a value of “SpamComplaint”.

Inbound messages #

In order to receive emails with Postmark you need to use our Inbound webhook. When you receive a new email at your inbound email address, it will look like the following, depending on the content of the email:

{
  "FromName": "Postmarkapp Support",
  "From": "support@postmarkapp.com",
  "FromFull": {
    "Email": "support@postmarkapp.com",
    "Name": "Postmarkapp Support",
    "MailboxHash": ""
  },
  "To": "\"Firstname Lastname\" <yourhash+SampleHash@inbound.postmarkapp.com>",
  "ToFull": [
    {
      "Email": "yourhash+SampleHash@inbound.postmarkapp.com",
      "Name": "Firstname Lastname",
      "MailboxHash": "SampleHash"
    }
  ],
  "Cc": "\"First Cc\" <firstcc@postmarkapp.com>, secondCc@postmarkapp.com>",
  "CcFull": [
    {
      "Email": "firstcc@postmarkapp.com",
      "Name": "First Cc",
      "MailboxHash": ""
    },
    {
      "Email": "secondCc@postmarkapp.com",
      "Name": "",
      "MailboxHash": ""
    }
  ],
  "Bcc": "\"First Bcc\" <firstbcc@postmarkapp.com>, secondbcc@postmarkapp.com>",
  "BccFull": [
    {
      "Email": "firstbcc@postmarkapp.com",
      "Name": "First Bcc",
      "MailboxHash": ""
    },
    {
      "Email": "secondbcc@postmarkapp.com",
      "Name": "",
      "MailboxHash": ""
    }
  ],
  "OriginalRecipient": "yourhash+SampleHash@inbound.postmarkapp.com",
  "Subject": "Test subject",
  "MessageID": "73e6d360-66eb-11e1-8e72-a8904824019b",
  "ReplyTo": "replyto@postmarkapp.com",
  "MailboxHash": "SampleHash",
  "Date": "Fri, 1 Aug 2014 16:45:32 -04:00",
  "TextBody": "This is a test text body.",
  "HtmlBody": "<html><body><p>This is a test html body.<\/p><\/body><\/html>",
  "StrippedTextReply": "This is the reply text",
  "Tag": "TestTag",
  "Headers": [
    {
      "Name": "X-Header-Test",
      "Value": ""
    },
    {
      "Name": "X-Spam-Status",
      "Value": "No"
    },
    {
      "Name": "X-Spam-Score",
      "Value": "-0.1"
    },
    {
      "Name": "X-Spam-Tests",
      "Value": "DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,SPF_PASS"
    }
  ],
  "Attachments": [
    {
      "Name": "test.txt",
      "Content": "VGhpcyBpcyBhdHRhY2htZW50IGNvbnRlbnRzLCBiYXNlLTY0IGVuY29kZWQu",
      "ContentType": "text/plain",
      "ContentLength": 45
    }
  ]
}

The inbound webhook is essential to a use case where you need to relay messages between two or more users in your application that should not know each other’s email addresses (like Twitter direct messages, eBay messages, a forum, etc). Using the MailboxHash key, you can keep track of which inbound messages belong to which email thread or conversation, and relay the emails between two or more recipients. When emails are sent to yourInboundAddress+hash@postmarkapp.com, we extract the hash part of the email address out so it can be used to keep track of the email and associated emails. Assign a unique value for the MailboxHash key and use it to determine the routing of the received email. You can then send the email content where it should be received by your user(s).

Open tracking #

The open tracking webhook will push messages to you when an email is opened and contains information such as the location, email client, and OS environment of the person who opened the email. Open tracking will need to be enabled for the email or server and can only be applied to HTML emails. You can choose to only receive notifications when an email is opened for the first time or every time an email is opened by enabling or disabling the setting “Post only on first open” in your Postmark server’s settings.

Open tracking notifications will be pushed in the following format:

    {
      "FirstOpen": true,
      "Client": {
        "Name": "Chrome 35.0.1916.153",
        "Company": "Google",
        "Family": "Chrome"
      },
      "OS": {
        "Name": "OS X 10.7 Lion",
        "Company": "Apple Computer, Inc.",
        "Family": "OS X 10"
      },
      "Platform": "WebMail",
      "UserAgent": "Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/35.0.1916.153 Safari\/537.36",
      "ReadSeconds": 5,
      "Geo": {
        "CountryISOCode": "RS",
        "Country": "Serbia",
        "RegionISOCode": "VO",
        "Region": "Autonomna Pokrajina Vojvodina",
        "City": "Novi Sad",
        "Zip": "21000",
        "Coords": "45.2517,19.8369",
        "IP": "188.2.95.4"
      },
      "MessageID": "883953f4-6105-42a2-a16a-77a8eac79483",
      "ReceivedAt": "2014-06-01T12:00:00",
      "Tag": "welcome-email",
      "Recipient": "john@example.com"
    }

You can use the data for your opens to determine which type of mail clients and operating systems your recipients use most, and tailor your emails to best suit those environments. You can also use these notifications to alert your users when important emails are opened or display the open date and time for them in a CRM or support case management application.

Delivery #

Once Postmark receives back a successful response from a receiving mail server, the email is considered delivered. Note that this means the receiving mail server accepted the email but may perform additional processing on it before delivering it to the final recipient. Postmark does not have access to the additional events that occur after the receiving mail server possesses the email, since those are internal to the receiving email server.

Delivery webhooks let you receive an event when this occurs for an email you sent that includes the receiving mail server’s response and details. Receiving delivery notifications in real time lets you update your application and/or database to show the events and let your user’s know the email was successfully delivered.

The JSON schema for a delivery webhook event is:

{
  "ServerId": 1234,
  "MessageID": "cd876b97-3308-4da8-999d-0fa7b0f89087",
  "Recipient": "john@example.com",
  "Tag": "your-tag",
  "DeliveredAt": "2014-08-01T13:28:10.2735393-04:00",
  "Details": "Test delivery webhook details"
}

The ServerId field tells you which server in Postmark the email was sent from. Using the MessageID, you can grab the email’s details (subject, sender, HTML body, etc…) with the Messages API. With the Recipient field you can tell who the email was sent to. If you added a Tag to the email when you sent it, you can get that back with the Tag field. DeliveredAt gives you the timestamp of when we received confirmation from the receiving mail server that they accepted the email. Details provides you with the response message from the receiving mail server.

Some common use cases of the delivery webhook include:

  • Feeding delivery events into a variety of internal systems to trigger additional actions on your end (such as update user information in your CRM)
  • Provide delivery events directly to your customers through a custom UI
  • Aggregate delivery events to calculate when there are delivery slowdowns and set thresholds to take action (such as switching to a backup service)

Testing and development #

Testing your webhook URL is essential to ensuring you efficiently use all the pushed data you receive. 

RequestBin #

To see real examples of our webhooks before starting development, we recommend using RequestBin. Navigate to https://requestb.in and click ‘Create a RequestBin’. This will create a publicly exposed URL where you can receive and inspect HTTP POSTs. Head into Postmark and open a Postmark server you wish to use for testing. In the server’s settings tab, set the URL for bounce, open tracking, and/or inbound webhooks to your new RequestBin URL that you created. Click ‘Save’ once you have set the URL(s) and we will then send webhook POSTs to your RequestBin URL. 

cURL #

For initial development work around receiving POSTs at your URL, using cURL is my favorite method. From a bash shell with cURL available, you can send a POST to your localhost that matches our JSON schema to ensure you can receive the data we send you at that URL and process it correctly. For example to test if your url of /webhooks/bounces can receive and properly process or store bounce webhook data, use the following cURL command from Terminal in macOS or a Linux OS:

curl localhost:3000/webhooks/bounces \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{ "ID": 42, "Type": "HardBounce", "TypeCode": 1, "Name": "Hard bounce", "Tag": "Test", "MessageID": "883953f4-6105-42a2-a16a-77a8eac79483", "Description": "The server was unable to deliver your message (ex: unknown user, mailbox not found).", "Details": "Test bounce details", "Email": "john@example.com", "BouncedAt": "2014-08-01T13:28:10.2735393-04:00", "DumpAvailable": true, "Inactive": true, "CanActivate": true, "Subject": "Test subject" }'

In the above example we use localhost:3000 but you will need to change this depending on the port your local web server runs on when you launch your app or site locally. For example if your app runs locally on port 8080, you would change the URL to POST to localhost:8080. Be sure your app is fully initialized locally before attempting to POST to your URL(s) and check the results. In our webhooks documentation you can see example JSON for each of the webhooks that you can use for testing your URLs.

Security #

In order to use webhooks, you have to publicly expose URLs that either you or a provider host. It is important to ensure that these exposed URLs cannot receive malicious POSTs. To prevent unauthorized or malicious messages at your URL(s), there are a few steps you can take. 

Postmark lists our IPs we use to send webhook event data here. Check incoming HTTP requests for the request’s IP address and if it does not match an IP address we list, reject the request. 

Another security step is to validate the data received, depending on the URL and webhook type. Check the body of the incoming request to ensure it matches the JSON schema of our webhooks, and does not include additional data. This will also prevent receiving webhooks at the wrong URL, for example receiving a bounce at your inbound URL if a Postmark server is incorrectly configured.

An additional step you can take is to specifically only allow the HTTP POST method to be used with your URL. You can prevent GET, PUT, and DELETE HTTP requests from being processed and whitelist only the POST method.

Example #

If you want to see an example application of how to receive, process, and display Postmark’s webhooks, head over to my project on GitHub here. You can play around with your own instance of the application by using the Deploy to Heroku button available in the repository. It was built using Meteor.js so if you are familiar with JavaScript, you can clone the repository and use it as a base for designing your own application for receiving Postmark’s webhooks.

Conclusion #

You now have some ideas of how Postmark’s webhooks work, some typical use cases, and best practices for security. Check out the section below for our webhooks documentation and start taking advantage of Postmark webhooks today!

Further reading #

Postmark Webhooks Overview
Bounce webhook
Inbound webhook
Open tracking webhook
Open tracking documentation
HTTP POST Overview