Postmark

Postmark Outbound

Postmark Inbound

Message Retrieval

Account API

Send Email with API

Sending mails through Postmark is as simple as sending HTTP Post request to the service. A line of code speaks more than a thousand words – the example below sends a message straight through curl. Execute it in your terminal to the see results (Mac and Linux).

$: curl -X POST "http://api.postmarkapp.com/email" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "X-Postmark-Server-Token: ed742D75-5a45-49b6-a0a1-5b9ec3dc9e5d" \
-v \
-d "{From: 'sender@example.com', To: 'receiver@example.com', Subject: 'Postmark test', HtmlBody: '<html><body><strong>Hello</strong> dear Postmark user.</body></html>'}"

Note that you can also use SSL encryption by issuing requests to https://api.postmarkapp.com/email.

Authentication headers

In order to authenticate yourself to the service, you need to send the correct HTTP header with the API key of your server:

X-Postmark-Server-Token: your-api-key-here

The header name and value are case insensitive. Should you execute the request with wrong or missing headers, you will receive HTTP Response 401 (Unauthorized).

Often when implementing your client library or when integrating an existing library into your application you would want to send “test” emails that don’t actually get delivered to the recipient. You just need to know if your data is valid. You can do that by passing the “POSTMARK_API_TEST” value as your server API token.

Message format

Currently Postmark supports JSON message format. The mail message format is

{
  "From" : "sender@example.com",
  "To" : "receiver@example.com",
  "Cc" : "copied@example.com",
  "Bcc": "blank-copied@example.com",
  "Subject" : "Test",
  "Tag" : "Invitation",
  "HtmlBody" : "<b>Hello</b>",
  "TextBody" : "Hello",
  "ReplyTo" : "reply@example.com",
  "Headers" : [{ "Name" : "CUSTOM-HEADER", "Value" : "value" }]
}

You should pass the json encoded message in the body of the request. Both from and to accept name, in the format of John Doe <email@example.com>. You can provide HtmlBody for html formatted messages, TextBody for plain text, or both for multipart. Multipart sends html with a text version for clients that don’t support html. Passing headers is optional.

  1. You should have a registered and confirmed sender signature with the sender email. Otherwise you will receive HTTP Response 422 (Unprocessable Entity).
  2. It is possible to override the Name in the sender signature through the API. This is useful if you want to use member’s information in the email while keeping your from email address. just pass the name in the From parameter, From: "John Smith <sender@example.com>".
  3. You can pass multiple recipient addresses in the ‘To’ field and the optional ‘Cc’ and ‘Bcc’ fields. Separate multiple addresses with a comma. Note that Postmark has a limit of twenty recipients per message in total. You need to take care not to exceed that limit. Otherwise you will get an error.
  4. You can categorize outgoing email using the optional Tag property. If you use different tags for the different types of emails your application generates, you will be able to get detailed statistics for them through the Postmark user interface.
  5. For email addresses that have names or titles with commas or other punctuation, you should quote them as such:
    "To" : "\"Joe Receiver, jr\" <receiver@example.com>",

Attachments

Attachments are specified in the Attachments array property. An attachment is an object that has to provide the file name (via the Name property), the content type (ContentType property) and the actual binary data (Content property) that has to be sent with the message.

The name is the actual file name that will be displayed to the message recipient. Note that the file extension is important. To eliminate the possibility of spreading viruses or spyware we allow only a number of file types. That is, instead of using a list of forbidden files and risking an unanticipated file type spreading infections, we have taken the opposite approach — we whitelist document file types that we are certain are safe. Here is the list of allowed files:

  • Documents: txt, rtf, htm, html, xml, ics, pdf, log, csv, tsv, doc, docx, dot, dotx, ppt, pptx, xls, xlsx, odt, psd, ai, vcf, mobi, epub, pgp, ods, wps, pages, stl, ppt, xls, doc, dat, pkpass, mms, mmr, json, pcm, mpp, mpp, mppx, vsd, vsdx, vsdm, rpt, oxps, ftil, indd, otf
  • Archives: zip, tar, tgz, bz2, gz, gzip, 7z, lzh, lza, rar, arj, hqx
  • Images: gif, jpg, jpeg, png, swf, dcr, tif, tiff, bmp, ico, page-icon, svg
  • Audio: wav, mp3, aif
  • Video: flv, avi, mpg, wmv, rm, mov, 3gp, mp4, m4a, ogv, wma
  • Misc: prn, ps, eps, license, lic, dcm, enc, cdr, css, pst, mobileconfig, eml, pkpass, crx, vcs
  • Geo: gpx, kml, kmz, msl
  • Coding: rb, js, java, c, cpp, py, php, fl, jar, r
  • Fonts: ttf, ttc
  • Customers: vpv, iif, timo, autorit, cathodelicense, lix, bind, edi, llv, jpi, bsx, lxf, ldraw, onepassword-license, emz, ab1, analysis, ape, cdx, CEL, clj, clustalw, config, descriptors, dna, gal, gb, gbk, ma4, mht, mol, MPD, msg, ncd, ndf, ngd, p7s, project, pse, pzf, sbd, sdf, seq, sf3, sigimg0, skc, STEP, str, user, webloc, xad
  • Navigation: itn, freshroute

Contact us if you feel we need to whitelist a file that your application needs.

The content type is the MIME content type that email clients use to interpret various attachments such as: text/plain, text/html, image/jpeg, etc. Your code can either detect it by the file extension, use a third party library to infer it, ask the user to provide it or just default to application/octet-stream.

The binary data has to be transmitted as a base64-encoded string. Most programming languages and libraries have this built in e.g. Java, .NET, PHP, Ruby

Here is a sample request containing attachments:

{
  "From" : "sender@example.com",
  "To" : "receiver@example.com",
  "Subject" : "Test",
  "HtmlBody" : "<b>Hello</b>",
  "TextBody" : "Hello",
  "Headers" :  [{ "Name" : "CUSTOM-HEADER", "Value" : "value" }],
  "Attachments": [
    {
      "Name": "readme.txt",
      "Content": "dGVzdCBjb250ZW50",
      "ContentType": "text/plain"
    },
    {
      "Name": "report.pdf",
      "Content": "dGVzdCBjb250ZW50",
      "ContentType": "application/octet-stream"
    }
  ]
}

Limitations:

  • Only allowed file types can be sent as attachments. The message will be rejected (or you will get an SMTP API bounce if using SMTP) with a description of the rejected file, if you try to send a file with a disallowed extension.
  • Attachment size can be 10 MB at most. That means you can send three attachments weighing at three megabytes each, but you won't be able to send a single 11MB attachment. Don't worry about base64 encoding making your data larger than it really is. Attachment size is calculated using the real binary data (after base64-decoding it).
  • Many applications can get away with sending email as a response to a user action and do that right in the same web request handler. Sending attachments changes that. Message size can and will get bigger and the time to submit it to the Postmark servers will get longer. That is why we recommend that you send email with attachments from a background job. Your users will love you for that!

Inline Image Attachments

You may pass inline images through Postmark via html messages using the API as well. In order to use this feature, you'll have to base64 encode your image(s) and then specify their ContentID (cid) in the API call as demonstrated below.

{
    "From": "sender@example.com",
    "To": "receiver@example.com",
    "Subject": "Inline Sending",
    "HtmlBody": "<html><head><meta http-equiv=\"content-type\" content=\"text/html; charset=ISO-8859-1\"></head><body text=\"#000000\" bgcolor=\"#FFFFFF\">test<br><img alt=\"bacon\" src=\"cid:part1.01030607.06070005@gmail.com\" width=\"600\" height=\"442\"><br></body></html>",
    "TextBody": "Inline",
    "Attachments": [
        {
            "Name": "bacon.jpg",
            "Content": "/9j/4AAQSkZJRgABAgEAAAAAAAD/4",
            "ContentType": "image/jpeg",
            "ContentID": "cid:part1.01030607.06070005@gmail.com"
        }
    ]
}

Postmark will then automatically embed the images inline with your html as long as the cid tags match your html code sections. NOTE: If you are referring to an attached image more than once in your message, it is only required to attach the image one time. Postmark will use the image as often as it is referred to in your html markup. This will save bandwidth against the attachment size limit.

Success

If all goes well, you will get back a JSON message looking a lot like:

{
  "ErrorCode" : 0,
  "Message" : "OK",
  "MessageID" : "b7bc2f4a-e38e-4336-af7d-e6c392c2f817",
  "SubmittedAt" : "2010-11-26T12:01:05.1794748-05:00",
  "To" : "receiver@example.com"
}

Note the MessageID property. You can log it in your system and use it to associate the message you just sent to a possible bounce that you obtained from a bounce web hook or the bounce API.

Batching messages

While Postmark is focused on transactional email, we understand that developers with higher volumes or processing time constraints need to send their messages in batches. To facilitate this we provide a batching endpoint that permits you to send up to 500 well-formed Postmark messages in a single API call.

The format of the batched message is a JSON array containing multiple message requests like the following example.

$: curl -X POST "http://api.postmarkapp.com/email/batch" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "X-Postmark-Server-Token: ed742D75-5a45-49b6-a0a1-5b9ec3dc9e5d" \
-v \
-d "[{From: 'sender@example.com', To: 'receiver1@example.com', Subject: 'Postmark test #1', HtmlBody: '<html><body><strong>Hello</strong> dear Postmark user.</body></html>'},{From: 'sender@example.com', To: 'receiver2@example.com', Subject: 'Postmark test #2', HtmlBody: '<html><body><strong>Hello</strong> dear Postmark user.</body></html>'}]"

Note that you can also use SSL encryption by issuing requests to https://api.postmarkapp.com/email/batch.

Similarly, you will receive a matching JSON array containing each response for the messages you sent in your batched call:

[
    {
      "ErrorCode" : 0,
      "Message" : "OK",
      "MessageID" : "b7bc2f4a-e38e-4336-af7d-e6c392c2f817",
      "SubmittedAt" : "2010-11-26T12:01:05.1794748-05:00",
      "To" : "receiver1@example.com"
    },
    {
      "ErrorCode" : 0,
      "Message" : "OK",
      "MessageID" : "e2ecbbfc-fe12-463d-b933-9fe22915106d",
      "SubmittedAt" : "2010-11-26T12:01:05.1794748-05:00",
      "To" : "receiver2@example.com"
    }
]

HTTP response codes

200 – Success
Everything went smooth.
401 – Unauthorized
Missing or incorrect API Key header.
422 – Unprocessable Entity
Something with the message is not quite right (either malformed JSON or incorrect fields). In this case, the response body contains JSON {ErrorCode: 405, Message: "details"} with an error code and an error message containing details on what went wrong.
500 – Internal Server Error
As you may guess, this one is our fault :( (we promise we will do our best so this does not happen!). Unfortunately, in this case you can be sure that the message is lost. We are notified in such cases, so rest assured that someone is already looking into the issue.

API error codes

Whenever the Postmark server detects an input error it will return an HTTP 422 status code along with a JSON object containing error details: {ErrorCode: 405, Message: "details"}. The ErrorCode field can be used to programmatically detect the type of error. Here are the supported error codes:

10 – Bad or missing API token
Your request did not submit the correct API token in the X-Postmark-Server-Token header.
300 – Invalid email request
Validation failed for the email request JSON data that you provided.
400 – Sender Signature not found
You are trying to send email with a From address that does not have a sender signature.
401 – Sender signature not confirmed
You are trying to send email with a From address that does not have a corresponding confirmed sender signature.
402 – Invalid JSON
The JSON input you provided is syntactically incorrect.
403 – Incompatible JSON
The JSON input you provided is syntactically correct, but still not the one we expect.
405 – Not allowed to send
You ran out of credits.
406 – Inactive recipient
You tried to send to a recipient that has been marked as inactive. Inactive recipients are ones that have generated a hard bounce or a spam complaint.
409 – JSON required
Your HTTP request does not have the Accept and Content-Type headers set to application/json.
410 – Too many batch messages
Your batched request contains more than 500 messages.