Postmark

Postmark Outbound

Postmark Inbound

Parse an email with Postmark

A server’s inbound mailbox is a unique hash generated when the server is created. Likely you will not share this mailbox identity directly with your customer, but instead set up email forwarding (i.e. from inbound@yourapp.com to yourhash@inbound.postmarkapp.com). Read our help article on forwarding to an inbound address. Your unique hash is provided in the InboundHash property of the JSON object returned from the GET /server command.

If you haven't already, you may want to review the process of configuring your inbound server.

When an email is received by Postmark at your unique mailbox address, it is immediately sent the hook URL you provided for that mailbox during configuration. The HTTP POST will contain a JSON body similar to the following:

{
 "Attachments": [
    {
     "Content": "[BASE64]",
     "ContentType": "image\/png",
     "Name": "myimage.png"
    },
    {
     "Content": "[BASE64]",
     "ContentType": "application\/msword",
     "Name": "mypaper.doc"
    }
 ],
 "Cc": "",
 "From": "\"My User\" ",
 "Headers": [
    {
     "Name": "MIME-Version",
     "Value": "1.0"
    },
    {
     "Name": "Date",
     "Value": "Thu, 24 Mar 2011 15:59:30 -0400"
    },
    {
     "Name": "Subject",
     "Value": "Welcome to Postmark"
    },
    {
     "Name": "From",
     "Value": "user@email.com"
    },
    {
     "Name": "To",
     "Value": "451d9b70cf9364d23ff6f9d51d870251569e+ahoy@inbound.postmarkapp.com"
    },
    {
     "Name": "Content-Type",
     "Value": "multipart\/mixed"
    },
    {
      "Name": "X-Spam-Checker-Version",
      "Value": "SpamAssassin 3.3.1 (2010-03-16) on rs-mail1"
    },
    {
      "Name": "X-Spam-Status",
      "Value": "No"
    },
    {
      "Name": "X-Spam-Score",
      "Value": "-0.8"
    },
    {
      "Name": "X-Spam-Tests",
      "Value": "DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,RCVD_IN_DNSWL_LOW"
    },
    {
      "Name": "Received-SPF",
      "Value": "Pass (sender SPF authorized) identity=mailfrom; client-ip=209.85.160.42; helo=mail-pw0-f42.google.com; envelope-from=support@postmarkapp.com; receiver=451d9b70cf9364d23ff6f9d51d870251569e+ahoy@inbound.postmarkapp.com"
    }
 ],
 "HtmlBody": "[HTML(encoded)]",
 "MailboxHash": "ahoy",
 "MessageID": "22c74902-a0c1-4511-804f2-341342852c90",
 "ReplyTo": "",
 "Subject": "This is an inbound message",
 "Tag": "",
 "TextBody": "[ASCII]",
 "To": "451d9b70cf9364d23ff6f9d51d870251569e+ahoy@inbound.postmarkapp.com"
}
      

With the JSON data above, you can easily process the email data into your application, including all included email headers, content, and attachments. It will be up to you to choose how you process the data, since it depends heavily on the use case, programming language, and environment.

Code Examples

To help you get started, we’ve collected some community developed examples & “mitts”, or code designed to “catch” Postmark Inbound webhook JSON.

Ruby Gem

PHP

Python

Node.js

We are actively looking for your contributions for other languages. If you write a code sample or library for Postmark Inbound, please email us at support@postmarkapp.com. Contributions are appreciated and rewarded with free Postmark credits. If you have questions, problems, or ideas for how to improve this API, we have a low-traffic API developer email list that you can join as well.

Helpful Custom Information

We add some extra custom data to emails that are processed which can be useful as you process messages. Here is a list and description of each piece of information:

MailboxHash

If your users send email to an email address that includes a custom hash after the mailbox name (user+hash@yourdomain.com) Postmark will split that hash out into it's own field. You can see the example above as "MailboxHash": "ahoy". This is useful for linking replies to outbound messages and other tasks where you want to tie the inbound message to a specific item in your application.

Attachments

Postmark will happily support attachments from your senders and include them in the JSON object as a tuple of filename, a mime content type, and the base64 encoded data.

For example, if a sender attaches an image, cat.jpeg, to their email, the following JSON structure is generated:

{
   "Attachments":[
      {
         "Content":"/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/wAARCAAwADADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDg7nQ9XlmtLWPTbku9wg5jIA5zknsPevbvBXhjTdPRXvJUubleW5+RT7D+prlRq32WFpWb5+w9qzrTxFMrqyySlyMhR1J/Dmvl62aNyUGtArNqXLE9+tNSs4IFRpB6cdfpWX4slsdQszGzblUhlZTgow6Mp9Qa8lXxFqEeQ0bRrkACVtgyfYkUsmu3sbhneHDHgeepz9eaueLpyp8ljD2VTojSuLhNQeWz1FwL+3+5Oox5qdmI/nWDdu0bPC55U4NUp9Tkn1aGSMoZERg21wfl69vxrT0fTpPEV61skyx3WwtFu4D46g+9eLWwbrNKC978z0sFiJUXyVNvyOR1q4un1E2sTFV3Dn2xzVPxN4qbwwZoI7Ca5iwpMm8ouCDnBHNb99FG80h2jcQPyq9p+lQanb7poEkOMHcM9AAQfyruwc4OpaSuPl/eNI47Rtf0DxKkV4iNFcQuu+OX1/vA/wAQ7ZFHjrxNc6fbQWfh+wM9wSz7kiL+SvQHb6nP6VoeJfDjxTi80i1U/ZQdwGApXHIAHXFS+EdNuJ7U6vfwqUuiDHsJ3bBwMg/nXalBS5re72OhwbjYzfAEfiImK91i6maWSVd8WFVQp4xwOeDzXXeE79tO8W2xHL293sI/2Twf0JrVuLa1t7FZFUgLgjjvmuZmRk8bXAU9HLfjsJrGtUftIzRxV4bF+ewvjI0hsZyFPeM4xT7HUlsLS6OGKqpfjqB3rqvFOszaZZkQ8tIhB78e3vXl15qpgnWGGPDj5pFJyCT2zWMMHKmlNanRUfNLmOl0nVbTW7XYsvkRHtnDGpgINKgCQXO4AdCcjFc5p9iNzTonlbuVQnpV9bIRQt50oZic5zx+FdShJo1UtCZtTfUNXsrN+I3cMwHcDn+lJApk8QXt86OyKG5UZxngH8s0y3gjF0bu3kTzQhVQTwuRjNa/hieDS4/MEglcH98c/eHfHtRTpKVVKWyOetG7uj//2Q==",
         "ContentLength":1357,
         "ContentType":"image/jpeg",
         "Name":"cat.jpeg"
      }
   ],
   "Cc":"",
   "Dump":null,
   "From":"\"Some Cat Fan\" ",
   "Subject":"Hello World!",
   "To":"76fa022d4a33c45ddf5be8c24c47f4da@inbound.postmarkapp.com"
}

You will then need to decode the content to generate the original attachment file. The following is a python snippet for doing so:

from base64 import b64decode

for attachment in inbound_json["attachment"]:
    blob = b64decode(attachment["Content"])
    file = open(attachment["Name"],"w")
    file.write(blob)
    file.close()

The formats supported for attachments are gif, jpg, jpeg, png, swf, flv, avi, mpg, mp3, mp4, ogv, wav, rm, mov, psd, ai, tif, tiff, txt, rtf, htm, html, pdf, epub, mobi, doc, docx, ppt, pptx, xls, xlsx, ps, eps, iif, log, csv, ics, xml and zip.

SpamAssassin Headers

By default, Postmark will accept any emails that are sent to your inbound address, including spam. If you're using Gmail forwarding, their filters will take care of much of this for you. To make it easier to find and filter spam that is sent to your app, we scan all inbound emails using SpamAssassin, and add a few unique headers to the header content. For example:

  • X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on rs-mail1 - Know the version of SpamAssassin that checked your inbound email.
  • X-Spam-Status: No - Either Yes or No depending on how SpamAssassin considers the message.
  • X-Spam-Score -0.8 - The spam score of the message, ranging from a negative (better) to positive (worse) number. The default consideration of spam is a score above 5.
  • X-Spam-Tests: DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,RCVD_IN_DNSWL_LOW - The series of tests that were triggered when processing the message. A full list of the test can be found at http://spamassassin.apache.org/tests_3_3_x.html

Note: While SpamAssassin is a powerful and effective tool, it is possible that legitimate messages could be marked with a higher score. We recommend thorough testing before filtering spam messages into your app.

SPF Headers

In addition to spam, it is also helpful to know if the identity of the sender is legitimate. SPF goes a long way for this. We check the from address of the email and check the SPF record, then add a header to the email with a result. It looks something like this:

Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=209.85.160.42; helo=mail-pw0-f42.google.com; envelope-from=support@postmarkapp.com; receiver=451d9b70cf9364d23ff6f9d51d870251569e+ahoy@inbound.postmarkapp.com

There are three possible states:

  • Received-SPF: neutral - A record does not exists and is neither permitted nor denied.
  • Received-SPF: pass - a record exists and the IP is approved for sending email.
  • Received-SPF: fail - a record exists and the IP is not approved for sending email.