postal Documentation

A fully featured open source mail delivery platform for incoming & outgoing e-mail

16,713 stars Ruby Ruby 1 file ยท ~10,314 tokens #mail#mail-server#postal#ruby#smtp
RAW Doc

Docker & Self-Hosted Deployment Verified OCI

Deploy postal on any server, homelab, or cloud container platform.

1-Click Terminal Command
bash (docker run)
docker run -d --name postal --restart always mariadb
Configured Services & Ports
โš™๏ธ postal
image: ${POSTAL_IMAGE}
โš™๏ธ mariadb
image: mariadb
docker-compose.yml
yaml (docker-compose.yml)
services:
  postal:
    image: ${POSTAL_IMAGE}
    depends_on:
      - mariadb
    entrypoint: ["/docker-entrypoint.sh"]
    volumes:
      - "./docker/ci-config:/config"
    environment:
      POSTAL_SIGNING_KEY_PATH: /config/signing.key
      MAIN_DB_HOST: mariadb
      MAIN_DB_USERNAME: root
      MESSAGE_DB_HOST: mariadb
      MESSAGE_DB_USERNAME: root
      LOGGING_ENABLED: "false"
      RAILS_ENVIRONMENT: test
      RAILS_LOG_ENABLED: "false"
      WAIT_FOR_TIMEOUT: 90
      WAIT_FOR_TARGETS: |-
        mariadb:3306

  mariadb:
    image: mariadb
    restart: always
    environment:
      MARIADB_DATABASE: postal
      MARIADB_ALLOW_EMPTY_PASSWORD: 'yes'
      MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: 'yes'

1. Project Overview & Quickstart (postalserver/postal)

File: README.md

Postal is a complete and fully featured mail server for use by websites & web servers. Think Sendgrid, Mailgun or Postmark but open source and ready for you to run on your own servers.


File: doc/config/configuration.md

Configuring Postal

Postal can be configured in two ways: using a YAML-based configuration file or through environment variables.

If you choose to use environment variables, you don't need to provide a config file. A full list of environment variables is available in the environment-variables.md file in this directory.

To use a configuration file, the POSTAL_CONFIG_FILE_PATH environment variable will dictate where Postal will look for the config file. An example YAML file containing all available configuration is provided in the yaml.yml file in this directory. Remember to include the version: 2 key/value in your configuration file.

Development

When developing with Postal, you can configure the application by placing a configuration file in config/postal/postal.yml. Alternatively, you can use environment variables by placing configuration in .env in the root of the application.

Running tests

By default, tests will use the config/postal/postal.test.yml configuration file and the .env.test environment file.

Containers

Within a container, Postal will for a config file in /config/postal.yml unless overriden by the POSTAL_CONFIG_FILE_PATH environment variable.

Ports & Bind Addresses

The web & SMTP server listen on ports and addresses. The defaults for these can be set through configuration however, if you're running multiple instances of these on a single host you will need to specify different ports for each one.

You can use the PORT and BIND_ADDRESS environment variables to provide instance-specific values for these processes.

Additionally, HEALTH_SERVER_PORT and HEALTH_SERVER_BIND_ADDRESS can be used to set the port/address to use for running the health server alongside other processes.

Legacy configuration

Legacy configuration files from Postal v1 and v2 are still supported. If you wish to use a new configuration option that is not available in the legacy format, you will need to upgrade the file to version 2.


File: doc/config/environment-variables.md

Environment Variables

This document contains all the environment variables which are available for this application.

Name Type Description Default
POSTAL_WEB_HOSTNAME String The hostname that the Postal web interface runs on postal.example.com
POSTAL_WEB_PROTOCOL String The HTTP protocol to use for the Postal web interface https
POSTAL_SMTP_HOSTNAME String The hostname that the Postal SMTP server runs on postal.example.com
POSTAL_USE_IP_POOLS Boolean Should IP pools be enabled for this installation? false
POSTAL_DEFAULT_MAXIMUM_DELIVERY_ATTEMPTS Integer The maximum number of delivery attempts 18
POSTAL_DEFAULT_MAXIMUM_HOLD_EXPIRY_DAYS Integer The number of days to hold a message before they will be expired 7
POSTAL_DEFAULT_SUPPRESSION_LIST_AUTOMATIC_REMOVAL_DAYS Integer The number of days an address will remain in a suppression list before being removed 30
POSTAL_DEFAULT_SPAM_THRESHOLD Integer The default threshold at which a message should be treated as spam 5
POSTAL_DEFAULT_SPAM_FAILURE_THRESHOLD Integer The default threshold at which a message should be treated as spam failure 20
POSTAL_USE_LOCAL_NS_FOR_DOMAIN_VERIFICATION Boolean Domain verification and checking usually checks with a domain's nameserver. Enable this to check with the server's local nameservers. false
POSTAL_USE_RESENT_SENDER_HEADER Boolean Append a Resend-Sender header to all outgoing e-mails true
POSTAL_SIGNING_KEY_PATH String Path to the private key used for signing $config-file-root/signing.key
POSTAL_SMTP_RELAYS Array of strings An array of SMTP relays in the format of smtp://host:port []
POSTAL_TRUSTED_PROXIES Array of strings An array of IP addresses to trust for proxying requests to Postal (in addition to localhost addresses) []
POSTAL_ALLOWED_REQUEST_DESTINATIONS Array of strings Hostnames or IP/CIDR ranges that outbound webhook and HTTP endpoint requests are permitted to reach even when they resolve to a private, loopback, link-local or otherwise reserved address. All other such destinations are blocked to prevent SSRF. []
POSTAL_QUEUED_MESSAGE_LOCK_STALE_DAYS Integer The number of days after which to consider a lock as stale. Messages with stale locks will be removed and not retried. 1
POSTAL_BATCH_QUEUED_MESSAGES Boolean When enabled queued messages will be de-queued in batches based on their destination true
WEB_SERVER_DEFAULT_PORT Integer The default port the web server should listen on unless overriden by the PORT environment variable 5000
WEB_SERVER_DEFAULT_BIND_ADDRESS String The default bind address the web server should listen on unless overriden by the BIND_ADDRESS environment variable 127.0.0.1
WEB_SERVER_MAX_THREADS Integer The maximum number of threads which can be used by the web server 5
WORKER_DEFAULT_HEALTH_SERVER_PORT Integer The default port for the worker health server to listen on 9090
WORKER_DEFAULT_HEALTH_SERVER_BIND_ADDRESS String The default bind address for the worker health server to listen on 127.0.0.1
WORKER_THREADS Integer The number of threads to execute within each worker 2
MAIN_DB_HOST String Hostname for the main MariaDB server localhost
MAIN_DB_PORT Integer The MariaDB port to connect to 3306
MAIN_DB_USERNAME String The MariaDB username postal
MAIN_DB_PASSWORD String The MariaDB password
MAIN_DB_DATABASE String The MariaDB database name postal
MAIN_DB_POOL_SIZE Integer The maximum size of the MariaDB connection pool 5
MAIN_DB_ENCODING String The encoding to use when connecting to the MariaDB database utf8mb4
MESSAGE_DB_HOST String Hostname for the MariaDB server which stores the mail server databases localhost
MESSAGE_DB_PORT Integer The MariaDB port to connect to 3306
MESSAGE_DB_USERNAME String The MariaDB username postal
MESSAGE_DB_PASSWORD String The MariaDB password
MESSAGE_DB_ENCODING String The encoding to use when connecting to the MariaDB database utf8mb4
MESSAGE_DB_DATABASE_NAME_PREFIX String The MariaDB prefix to add to database names postal
LOGGING_RAILS_LOG_ENABLED Boolean Enable the default Rails logger false
LOGGING_SENTRY_DSN String A DSN which should be used to report exceptions to Sentry
LOGGING_ENABLED Boolean Enable the Postal logger to log to STDOUT true
LOGGING_HIGHLIGHTING_ENABLED Boolean Enable highlighting of log lines false
GELF_HOST String GELF-capable host to send logs to
GELF_PORT Integer GELF port to send logs to 12201
GELF_FACILITY String The facility name to add to all log entries sent to GELF postal
SMTP_SERVER_DEFAULT_PORT Integer The default port the SMTP server should listen on unless overriden by the PORT environment variable 25
SMTP_SERVER_DEFAULT_BIND_ADDRESS String The default bind address the SMTP server should listen on unless overriden by the BIND_ADDRESS environment variable ::
SMTP_SERVER_DEFAULT_HEALTH_SERVER_PORT Integer The default port for the SMTP server health server to listen on 9091
SMTP_SERVER_DEFAULT_HEALTH_SERVER_BIND_ADDRESS String The default bind address for the SMTP server health server to listen on 127.0.0.1
SMTP_SERVER_TLS_ENABLED Boolean Enable TLS for the SMTP server (requires certificate) false
SMTP_SERVER_TLS_CERTIFICATE_PATH String The path to the SMTP server's TLS certificate $config-file-root/smtp.cert
SMTP_SERVER_TLS_PRIVATE_KEY_PATH String The path to the SMTP server's TLS private key $config-file-root/smtp.key
SMTP_SERVER_TLS_CIPHERS String Override ciphers to use for SSL
SMTP_SERVER_SSL_VERSION String The SSL versions which are supported SSLv23
SMTP_SERVER_PROXY_PROTOCOL Boolean Enable proxy protocol for use behind some load balancers (supports proxy protocol v1 only) false
SMTP_SERVER_LOG_CONNECTIONS Boolean Enable connection logging false
SMTP_SERVER_MAX_MESSAGE_SIZE Integer The maximum message size to accept from the SMTP server (in MB) 14
SMTP_SERVER_LOG_IP_ADDRESS_EXCLUSION_MATCHER String A regular expression to use to exclude connections from logging
DNS_MX_RECORDS Array of strings The names of the default MX records ["mx1.postal.example.com", "mx2.postal.example.com"]
DNS_SPF_INCLUDE String The location of the SPF record spf.postal.example.com
DNS_RETURN_PATH_DOMAIN String The return path hostname rp.postal.example.com
DNS_ROUTE_DOMAIN String The domain to use for hosting route-specific addresses routes.postal.example.com
DNS_TRACK_DOMAIN String The CNAME which tracking domains should be pointed to track.postal.example.com
DNS_HELO_HOSTNAME String The hostname to use in HELO/EHLO when connecting to external SMTP servers
DNS_DKIM_IDENTIFIER String The identifier to use for DKIM keys in DNS records postal
DNS_DOMAIN_VERIFY_PREFIX String The prefix to add before TXT record verification string postal-verification
DNS_CUSTOM_RETURN_PATH_PREFIX String The domain to use on external domains which points to the Postal return path domain psrp
DNS_TIMEOUT Integer The timeout to wait for DNS resolution 5
DNS_RESOLV_CONF_PATH String The path to the resolv.conf file containing addresses for local nameservers /etc/resolv.conf
SMTP_HOST String The hostname to send application-level e-mails to 127.0.0.1
SMTP_PORT Integer The port number to send application-level e-mails to 25
SMTP_USERNAME String The username to use when authentication to the SMTP server
SMTP_PASSWORD String The password to use when authentication to the SMTP server
SMTP_AUTHENTICATION_TYPE String The type of authentication to use login
SMTP_ENABLE_STARTTLS Boolean Use STARTTLS when connecting to the SMTP server and fail if unsupported false
SMTP_ENABLE_STARTTLS_AUTO Boolean Detects if STARTTLS is enabled in the SMTP server and starts to use it true
SMTP_OPENSSL_VERIFY_MODE String When using TLS, you can set how OpenSSL checks the certificate. Use 'none' for no certificate checking peer
SMTP_FROM_NAME String The name to use as the from name outgoing emails from Postal Postal
SMTP_FROM_ADDRESS String The e-mail to use as the from address outgoing emails from Postal [email protected]
RAILS_ENVIRONMENT String The Rails environment to run the application in production
RAILS_SECRET_KEY String The secret key used to sign and encrypt cookies and session data in the application
RSPAMD_ENABLED Boolean Enable rspamd for message inspection false
RSPAMD_HOST String The hostname of the rspamd server 127.0.0.1
RSPAMD_PORT Integer The port of the rspamd server 11334
RSPAMD_SSL Boolean Enable SSL for the rspamd connection false
RSPAMD_PASSWORD String The password for the rspamd server
RSPAMD_FLAGS String Any flags for the rspamd server
SPAMD_ENABLED Boolean Enable SpamAssassin for message inspection false
SPAMD_HOST String The hostname for the SpamAssassin server 127.0.0.1
SPAMD_PORT Integer The port of the SpamAssassin server 783
CLAMAV_ENABLED Boolean Enable ClamAV for message inspection false
CLAMAV_HOST String The host of the ClamAV server 127.0.0.1
CLAMAV_PORT Integer The port of the ClamAV server 2000
SMTP_CLIENT_OPEN_TIMEOUT Integer The open timeout for outgoing SMTP connections 30
SMTP_CLIENT_READ_TIMEOUT Integer The read timeout for outgoing SMTP connections 30
MIGRATION_WAITER_ENABLED Boolean Wait for all migrations to run before starting a process false
MIGRATION_WAITER_ATTEMPTS Integer The number of attempts to try waiting for migrations to complete before start 120
MIGRATION_WAITER_SLEEP_TIME Integer The number of seconds to wait between each migration check 2
OIDC_ENABLED Boolean Enable OIDC authentication false
OIDC_LOCAL_AUTHENTICATION_ENABLED Boolean When enabled, users with passwords will still be able to login locally. If disable, only OpenID Connect will be available. true
OIDC_NAME String The name of the OIDC provider as shown in the UI OIDC Provider
OIDC_ISSUER String The OIDC issuer URL
OIDC_IDENTIFIER String The client ID for OIDC
OIDC_SECRET String The client secret for OIDC
OIDC_SCOPES Array of strings Scopes to request from the OIDC server. ["openid", "email"]
OIDC_UID_FIELD String The field to use to determine the user's UID sub
OIDC_EMAIL_ADDRESS_FIELD String The field to use to determine the user's email address email
OIDC_NAME_FIELD String The field to use to determine the user's name name
OIDC_DISCOVERY Boolean Enable discovery to determine endpoints from .well-known/openid-configuration from the Issuer true
OIDC_AUTHORIZATION_ENDPOINT String The authorize endpoint on the authorization server (only used when discovery is false)
OIDC_TOKEN_ENDPOINT String The token endpoint on the authorization server (only used when discovery is false)
OIDC_USERINFO_ENDPOINT String The user info endpoint on the authorization server (only used when discovery is false)
OIDC_JWKS_URI String The JWKS endpoint on the authorization server (only used when discovery is false)

2. Official Technical Reference & Guides (postalserver/docs)

File: README.md

View the Site

๐Ÿ‘‰ See the live documentation site at https://docs.postalserver.io

Postal Server Documentation

Postal is a complete and fully-featured mail server for use by websites and web servers. Think of Sendgrid, Mailgun, or Postmark, but open source and ready for you to run on your own servers. Postal was developed by aTech Media to serve its own mail processing requirements, and we have since decided that it should be released as an open-source project for the community. It was originally launched by us as AppMail but was renamed to Postal as part of making it open source because we felt the name was more suitable.

The Purpose of This Repository

This repository hosts the documentation for Postal only. If you are looking for the GitHub repository for the application source code, go to the open-source repository for Postal โ†’

Contribution Instructions

Contributions are welcome! Please open up a pull request that clearly describes your intentions.

This site runs on Nuxt Content. Please review their documentation to understand how this framework works.

Local Development Setup

Follow these steps to get the site running on your local machine.

Prerequisites

We advise you to use NVM to manage node versions and enable PNPM using corepack.

NVM Setup

Change to the project directory

bash
cd /path/to/postal-docs

Install the correct Node version

bash
nvm install

Use the correct Node version

bash
nvm use

Enable PNPM

Corepack

PNPM is available by default; you just need to enable corepack.

bash
corepack enable pnpm

Prepare Your System

Change to the project directory

bash
cd /path/to/postal-docs

Install Dependencies

Install the Node dependencies using PNPM.

bash
pnpm install

Start the Development Web Server

Start the development server on http://localhost:3000

[!NOTE]
If you see a warning about a "Missing NUXT_UI_PRO_LICENSE", you can ignore that message. This is only used in production.

bash
pnpm dev

Your local development environment is now running. You can view the site at http://localhost:3000. Any changes you make to the content will be automatically reflected in the browser once you save the file.

How to Edit the Docs Content?

This documentation uses Nuxt Content and works on the following key concepts:

  • Content is stored as markdown files in the /content folder.
  • Pages are sorted by the number at the beginning of their MD file.
  • Pages need to have a title and description as their metadata.
  • You can use any Nuxt UI and Nuxt UI Pro prose component.

Example:

text
---
title: Feature List
---

# Feature List
Here you can write your content. 
...

---

## File: content/5.other/1.auto-responders-and-bounces.md

---
title: Auto-Responders & Bounces
---
When you send an e-mail you may be automatically be sent a bounce message or an auto responder by the destination mail server. These are handled slightly differently to normal incoming e-mail and it's worth understanding how these work.

Messages like these aren't usually sent to the e-mail address that sent the message but are sent to the **return path** address. This is an address which Postal assigns to your mail server and is provided to the destination mail server for the purpose of sending this type of message. The return to address will be something like `[email protected]`.

If you wish to route mail which is sent to your return path address to your application, you can set up a **return path route**. This is the same as a normal route except you should enter the name as `__returnpath__` and leave the domain field blank. You can only choose HTTP endpoints for this type of route. Once added, messages sent to your return path that aren't detected as bounces will be sent to HTTP endpoint you choose.

## A note about bounces

Messages that Postal detects as being bounces for a message you have already sent will not be delivered to your return path route. The original message will be updated and a `MessageBounced` webhook event will be triggered.

---

## File: content/5.other/2.containers.md

---
title: Our container image
---

This page contains information about how Postal actually is packaged and run within a container.

## Where's the container?

Postal is packaged and hosted at `ghcr.io/postalserver/postal`.

The `latest` tag will always track the `main` branch within the repository and therefore will have the latest copy of the application. It is not recommended to use this tag in production because you may start using it at any time without noticing.

Each version of Postal will also be tagged, for example, `3.0.0`. We always recommend using a version tag in production. To upgrade, you simply need to start using the newer version of the container and be sure to run the `upgrade` command. You can view all the tags which exist [on GitHub](https://github.com/postalserver/postal/pkgs/container/postal) and in [our CHANGELOG](https://github.com/postalserver/postal/blob/main/CHANGELOG.md).

## What processes need to run?

There are 3 processes that need to be running for a successful Postal installation. All processes are run within the same image (`ghcr.io/postalserver/postal`). The table below identifies the processes.

### The web server

- **Command:** `postal web-server`
- **Ports:** 5000

This is the main web server that handles all web traffic for Postal's admin interface and open/click tracking requests. By default, it listens on port 5000 but this can be configured in the `postal.yml` file by changing the `web_server.default_port` option or setting the `PORT` environment variable.

You can run multiple web servers and load balance between them to add additional capacity for web requests.

### The SMTP server

- **Command:** `postal smtp-server`
- **Ports:** 25
- **Capabilities required:** `NET_BIND_SERVICE`

This is the main SMTP server for receiving messages from clients and other MTAs. As with the web server, you can configure this to run on any port by changing the `smtp_server.default_port` option in the `postal.yml` config file or setting the `PORT` environment variable.

You can run multiple SMTP servers and load balance between them to add additional capacity for SMTP connections.

### The worker(s)

- **Command:** `postal worker`

This runs a worker which will receive jobs from the message queue. Essentially, this handles processing all incoming and outgoing e-mail. If you're needing to process lots of e-mails, you may wish to run more than one of these. You can run as many of these as you wish.

## Configuration

The image expects all configuration to be mounted at `/config`. At a minimum, this directory must contain a `postal.yml` and a `signing.key`. You can see a minimal example `postal.yml` in the [installation tool repository](https://github.com/postalserver/install/blob/main/examples/postal.v3.yml). For a full example, [see here](https://github.com/postalserver/postal/blob/main/doc/config/yaml.yml).

The `signing.key` can be generated using the following command:

openssl genrsa -out path/to/signing.key 2048

text
## Networking

If you wish to utilise IP pools, you will need to run Postal using host networking. This is because Postal will need to be able to determine which physical IPs are available to it and be able to send and receive traffic on those IPs.

If you are not using IP pools, there is no need to use host networking and you can expose the ports listed above as appropriate.

## Waiting for services

The container's entrypoint supports waiting for external services to be ready before starting the underlying process. To use this you need to set the `WAIT_FOR_TARGETS` environment variable with a list of services and ports. For example, `mariadb:3306`, replacing `mariadb` with the hostname or IP of your MariaDB server. You can specify multiple endpoint by separating them with a space.

The default maximum time to wait is 30 seconds, you can override this using the `WAIT_FOR_TIMEOUT` environment variable.

---

## File: content/5.other/3.debugging.md

---
title: Debugging
---

This page contains information on how to identify problems with your installation.

## DNS

Whilst Postal can verify DNS records on its own, it can be useful to check what the rest of the internet is seeing.

You can make use of [Whats My DNS](https://whatsmydns.net) for a quick global check or the `dig` command if you have it on a terminal, i.e. `dig txt yourdomain.com` or `dig a yourdomain.com`.

## SMTP

The quickest way to ensure the internet can connect to your Postal SMTP is with `telnet postal.yourdomain.com 25`. You can proceed to attempt sending a message manually if you are familiar with the raw SMTP commands to further verify your Postal installation is working correctly.

### SMTP SSL

If you aren't sure about whether the SSL certificate you have provided to Postal is set up correctly you can use `openssl s_client -connect postal.yourdomain.com:25 -starttls smtp` to get some information about your certificate from the point of view of SMTP.

---

## File: content/5.other/4.wildcards-and-address-tags.md

---
title: Wildcards & Address Tags
---
Postal supports the use of wildcards and address tags in routes.

## Using a wildcard

Wildcards will allow you to receive all e-mail for every address on a domain. However, for most use cases, this isn't recommended because it means that large volumes of spam may be processed by your mail server that would otherwise have been rejected by Postal without troubling you.

Just enter `*` in the name box to create a route for this.

## Using address tags

Postal supports the use of "tags" on e-mail addresses which means you can add a single route but still receive from multiple addresses. For example, if you add a route for `email` you will also receive messages for `[email protected]` without any additional configuration.

---

## File: content/4.developer/1.api.md

---
title: Using the API
---
The HTTP API allows you to send messages to us using JSON over HTTP. You can either talk to the API using your current HTTP library or you can use one of the pre-built libraries.

[Full API documentation](https://apiv1.postalserver.io)

::callout{icon="i-heroicons-information-circle"}
This API does not support managing all the functions of Postal. There are plans to introduce a new v2 API which will have more functionality and significantly better documentation. We do not have an ETA for this. Additionally, we will not be accepting any pull requests to extend the current API to have any further functionality than it currently does.
::

## General API Instructions

* You should send POST requests to the URLs shown below.
* Parameters should be encoded in the body of the request and `application/json` should be set as the `Content-Type` header.
* The response will always be provided as JSON. The status of a request can be determined from the `status` attribute in the payload you receive. It will be `success` or `error`. Further details can be found in the `data` attribute.

An example response body is shown below:

```javascript
{
  "status":"success",
  "time":0.02,
  "flags":{},
  "data":{"message_id":"xxxx"}
}

To authenticate to the API you'll need to create an API credential for your mail server through the web interface. This is a random string which is unique to your server.

To authenticate a request to the API, you need to pass this key in the X-Server-API-Key HTTP header.

Sending a message

There are two ways to send a message - you can either provide each attribute needed for the e-mail individually or you can craft your own RFC 2822 message and send this instead.

Full details about these two methods can be found in our API documentation:

For both these methods, the API will return the same information as the result. It will contain the message_id of the message that was sent plus a messages hash with the IDs of the messages that were sent by the server to each recipient.

javascript
{
  "message_id":"[email protected]",
  "messages":{
    "[email protected]":{"id":37171, "token":"a4udnay1"},
    "[email protected]":{"id":37172, "token":"bsfhjsdfs"}
  }
}

GET Message

To retrieve a message and its contents, use the GET method with the id (received when sending the message) and _expansions parameters (if you need more information than the basics) for the message from Postal. For more details, refer to the Postal API documentation.

json
{
  "id": 14,
  "_expansions": true
}

Example cURL Request

You can use the following cURL command to make the request:

bash
curl --location 'https://<your.postal.domain.com>/api/v1/messages/message' \
--header 'X-Server-API-Key: $yourAPIKeyFromTheCredentialsPage' \
--header 'Content-Type: application/json' \
--data '{
  "id": 14,
  "_expansions": true
}'

File: content/4.developer/2.client-libraries.md


title: Client Libraries

There are a number of client libraries available to help send e-mail using the Postal platform. These aren't all developed by the Postal team.

All of these libraries will make use of the API rather than using any SMTP protocol - this is considered to be best approach for delivering your messages.

If your framework makes use of SMTP, you do not need a client library however you will also miss out on some of Postals functionality.


File: content/4.developer/3.http-payloads.md


title: Receiving e-mail by HTTP

One of the most useful features in Postal is the ability to have incoming messages delivered to your own application as soon as they arrive. To receive incoming messages from Postal you can set it up to pass them to an HTTP URL of your choosing.

Each endpoint has an HTTP URL (we highly recommend making use of HTTPS where possible) as well as a set of rules which defines how data is sent to you.

  • You can choose whether data is encoded as normal form data or whether Postal sends JSON as the body of the request.
  • You can choose whether to receive the raw message (raw) or have it as a JSON dictionary (processed).
  • You can choose whether you'd like replies and signatures to be separated from the plain body of the message.

Your server should accept Postals incoming request and reply within 5 seconds. If it takes longer than this, Postal will assume it has failed and the request will be retried. Your server should send a 200 OK status to signal to Postal that you've received the request.

Messages will be tried up to 18 times with an exponential back-off until a successful response is seen except in the case of 5xx statuses which will fail immediately.

When a message permanently fails to be delivered to your endpoint (i.e. the server returned a 5xx status code or it wasn't accepted after 18 attempts), the recipient will be sent a bounce message.

You can view the attempts (along with debugging information) on the message page in the web interface.

The processed payload

When you chose to receive the message as JSON (processed), you'll receive a payload with the following attributes.

javascript
{
  "id":12345,
  "rcpt_to":"[email protected]",
  "mail_from":"[email protected]",
  "token":"rtmuzogUauKN",
  "subject":"Re: Welcome to AwesomeApp",
  "message_id":"[email protected]",
  "timestamp":1478169798.924355,
  "size":"822",
  "spam_status":"NotSpam",
  "bounce":false,
  "received_with_ssl":false,
  "to":"[email protected]",
  "cc":null,
  "from":"John Doe <[email protected]>",
  "date":"Thu, 03 Nov 2016 10:43:18 +0000",
  "in_reply_to":null,
  "references":null,
  "plain_body":"Hello there!",
  "html_body":"Hello there!",
  "auto_submitted":"auto-reply",
  "attachment_quantity":1,
  "attachments":[
    {
      "filename":"test.txt",
      "content_type":"text/plain",
      "size":12,
      "data":"SGVsbG8gd29ybGQh"
    }
  ]
}
  • You will only have the attachments attribute if you have enabled it.
  • The data attribute for each attachment is Base64 encoded.

The raw message payload

When you choose to receive the full message, you will receive the following attributes.

javascript
{
  "id":12345,
  "message":"REtJTS1TaWduYXR1cmU6IHY9MTsgYT1yc2Etc2hhMjU2Oy...",
  "base64":true,
  "size":859
}
  • The base64 attribute specifies whether or not the message attribute is encoded with Base64. This is likely to be true all the time.

File: content/4.developer/4.webhooks.md


title: Webhooks

Postal supports sending webhooks over HTTP when various events occur during the lifecycle of a message.

This page lists all the different types of event along with an example JSON payload that you'll receive. In many cases, only a small amount of information will be sent, if you require more information you should use the API to obtain it.

Message Status Events

These events are triggered on various events in an e-mail's lifecycle. The payload format is identical for all messages however the status attribute may change. The following statuses may be delivered.

  • MessageSent - when a message is successfully delivered to a recipient/endpoint.
  • MessageDelayed - when a message's delivery has been delayed. This will be sent each time Postal attempts a delivery and a message is delayed further.
  • MessageDeliveryFailed - when a message cannot be delivered.
  • MessageHeld - when a message is held.
javascript
{
  "status":"Sent",
  "details":"Message sent by SMTP to aspmx.l.google.com (2a00:1450:400c:c0b::1b) (from 2a00:67a0:a:15::2)",
  "output":"250 2.0.0 OK 1477944899 ly2si31746747wjb.95 - gsmtp",
  "time":0.22,
  "sent_with_ssl":true,
  "timestamp":1477945177.12994,
  "message":{
    "id":12345,
    "token":"abcdef123",
    "direction":"outgoing",
    "message_id":"[email protected]",
    "to":"[email protected]",
    "from":"[email protected]",
    "subject":"Welcome to AwesomeApp",
    "timestamp":1477945177.12994,
    "spam_status":"NotSpam",
    "tag":"welcome"
  }
}

Message Bounces

If Postal receives a bounce message for a message that was previously accepted, you'll receive the MessageBounced event.

javascript
{
  "original_message":{
    "id":12345,
    "token":"abcdef123",
    "direction":"outgoing",
    "message_id":"[email protected]",
    "to":"[email protected]",
    "from":"[email protected]",
    "subject":"Welcome to AwesomeApp",
    "timestamp":1477945177.12994,
    "spam_status":"NotSpam",
    "tag":"welcome"
  },
  "bounce":{
    "id":12347,
    "token":"abcdef124",
    "direction":"incoming",
    "message_id":"[email protected]",
    "to":"[email protected]",
    "from":"[email protected]",
    "subject":"Delivery Error",
    "timestamp":1477945179.12994,
    "spam_status":"NotSpam",
    "tag":null
  }
}

Message Click Event

If you have click tracking enabled, the MessageLinkClicked event will tell you that a user has clicked on a link in one of your e-mails.

javascript
{
  "url":"https://atech.media",
  "token":"VJzsFA0S",
  "ip_address":"185.22.208.2",
  "user_agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36",
  "message":{
    "id":12345,
    "token":"abcdef123",
    "direction":"outgoing",
    "message_id":"[email protected]",
    "to":"[email protected]",
    "from":"[email protected]",
    "subject":"Welcome to AwesomeApp",
    "timestamp":1477945177.12994,
    "spam_status":"NotSpam",
    "tag":"welcome"
  }
}

Message Loaded/Opened Event

If you have open tracking enabled, the MessageLoaded event will tell you that a user has opened your e-mail (or, at least, have viewed the tracking pixel embedded within it.)

javascript
{
  "ip_address":"185.22.208.2",
  "user_agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36",
  "message":{
    "id":12345,
    "token":"abcdef123",
    "direction":"outgoing",
    "message_id":"[email protected]",
    "to":"[email protected]",
    "from":"[email protected]",
    "subject":"Welcome to AwesomeApp",
    "timestamp":1477945177.12994,
    "spam_status":"NotSpam",
    "tag":"welcome"
  }
}

DNS Error Event

Postal regularly monitors domains it knows about to ensure that your SPF/DKIM/MX records are correct. If you'd like to be notified when the checks fail, you can subscribe to the DomainDNSError event.

javascript
{
  "domain":"example.com",
  "uuid":"820b47a4-4dfd-42e4-ae6a-1e5bed5a33fd",
  "dns_checked_at":1477945711.5502,
  "spf_status":"OK",
  "spf_error":null,
  "dkim_status":"Invalid",
  "dkim_error":"The DKIM record at example.com does not match the record we have provided. Please check it has been copied correctly.",
  "mx_status":"Missing",
  "mx_error":null,
  "return_path_status":"OK",
  "return_path_error":null,
  "server":{
    "uuid":"54529725-8807-4069-ab29-a3746c1bbd98",
    "name":"AwesomeApp Mail Server",
    "permalink":"awesomeapp",
    "organization":"atech"
  },
}

File: content/3.features/click-and-open-tracking.md


title: Click & Open Tracking category: Features

Postal supports tracking opens and clicks from e-mails. This allows you to see when people open messages or they click links within them.

How it works

Once enabled, Postal will automatically scan your outgoing messages and replace any links and images with new URLs that go via your Postal web server. When the link is clicked, Postal will log the click and redirect to the user to the original URL automatically. The links that are included in the e-mail should be on the same domain as the sender and therefore you need to configure a subdomain like click.yourdomain.com and point it to your Postal server.

Configuring your web server

To avoid messages being marked as spam, it's important that the subdomain that Postal uses in the re-written URLs is on the same domain as that sending the message. This means if you are sending mail from yourdomain.com, you'll need to setup click.yourdomain.com (or whatever you choose) to point to your Postal server.

There are two ways how to achive that traffic to click.yourdomain.com will reach Postal:

  1. Adding CNAME record for click.yourdomain.com to previously configured track.postal.example.com followed by Caddy additional configuration.
  2. Configuring custom proxy for click.yourdomain.com on your webserver.

Additional Caddy configuration

If you used Caddy as proxy for overall Postal traffic it easy to add additional proxy its config /opt/postal/config/Caddyfile:

text
# ... previous content

click.yourdomain.com {
  reverse_proxy 127.0.0.1:5000 {
    header_up X-Postal-Track-Host "1"
  }
}

After saving this new configuration restart Caddy, for example if you're using docker, you may be able to docker restart postal-caddy.

After this you should see Hello. on click.yourdomain.com and SSL should work out of the box.

Custom proxy on webserver

You'll need to add an appropriate virtual host on your web server that proxies traffic from that domain to the Postal web server. The web server must add the X-Postal-Track-Host: 1 header so the Postal web server knows to treat requests as tracking requests.

Once you have configured this, you should be able to visit your chosen domain in a browser and see Hello. printed back to you. If you don't see this, review your configuration until you do. If you still don't see this and you enable the tracking, your messages will be sent with broken links and images.

Setting up tracking domain

If you're happy things are working, you can enable tracking as follows:

  1. Find the web server you wish to enable tracking on in the Postal web interface
  2. Go to the Domains item
  3. Select Tracking Domains
  4. Click Add a tracking domain
  5. Enter the domain that you have configured and choose the configuration you want to use. It is highly recommended that you use SSL for these connections. Anything else is likely to cause problems with reputation and user experience.

Disabling tracking on a per e-mail basis

If you don't wish to track anything in an email you can add a header to your e-mails before sending it.

text
X-AMP: skip

If there are certain domains you don't wish to track links from, you can define these on the tracking domain settings page. For example, if you list yourdomain.com no links to this domain will be tracked.

If you wish to disable tracking for a particular link, you can do so by inserting +notrack as shown below. The +notrack will be removed leaving a plain link.

  • https+notrack://postalserver.io
  • http+notrack://katapult.io/signup