├── .editorconfig ├── .env.example ├── .eslintignore ├── .eslintrc.cjs ├── .github └── workflows │ ├── build-test.yml │ └── deploy.yml ├── .gitignore ├── .npmrc ├── .nvmrc ├── README.md ├── app.config.ts ├── app.vue ├── components ├── Footer.vue ├── Header.vue └── OgImage │ └── OgImageDocs.vue ├── content ├── 1.welcome │ ├── 1.feature-list.md │ ├── 2.faqs.md │ └── _dir.yml ├── 2.getting-started │ ├── 0.index.md │ ├── 1.prerequisites.md │ ├── 2.installation.md │ ├── 3.upgrading.md │ ├── 4.configuration.md │ ├── 4.dns-configuration.md │ ├── 5.upgrade-to-v3.md │ ├── 6.upgrade-to-v2.md │ └── _dir.yml ├── 3.features │ ├── _dir.yml │ ├── click-and-open-tracking.md │ ├── health-metrics.md │ ├── ip-pools.md │ ├── logging.md │ ├── oidc.md │ ├── smtp-authentication.md │ ├── smtp-tls.md │ └── spam-and-virus-checking.md ├── 4.developer │ ├── 1.api.md │ ├── 2.client-libraries.md │ ├── 3.http-payloads.md │ ├── 4.webhooks.md │ └── _dir.yml ├── 5.other │ ├── 1.auto-responders-and-bounces.md │ ├── 2.containers.md │ ├── 3.debugging.md │ ├── 4.wildcards-and-address-tags.md │ └── _dir.yml └── index.yml ├── error.vue ├── layouts └── docs.vue ├── nuxt.config.ts ├── nuxt.schema.ts ├── package.json ├── pages ├── [...slug].vue └── index.vue ├── pnpm-lock.yaml ├── public ├── CNAME.off ├── cover.png ├── factory.jpg ├── favicon.ico ├── icon.png ├── logo-dark.svg ├── logo-light.svg ├── preview-dark.png ├── preview.png ├── screenshot.png ├── screenshots.png ├── screenshots │ ├── Screen-Shot-2021-07-29-23-26-18.23-Qwv2DD40v4jMEoaHtE.png │ ├── oidc.png │ └── tracked-message.png └── supporters │ ├── katapult-dark.svg │ ├── katapult-light.svg │ ├── krystal-dark.svg │ └── krystal-light.svg ├── renovate.json ├── server ├── api │ └── search.json.get.ts └── tsconfig.json ├── tailwind.config.ts └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_size = 2 6 | indent_style = space 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | # Production license for @nuxt/ui-pro, get one at https://ui.nuxt.com/pro/purchase 2 | NUXT_UI_PRO_LICENSE= 3 | 4 | # Public URL, used for OG Image when running nuxt generate 5 | NUXT_PUBLIC_SITE_URL= 6 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | .output 4 | .nuxt 5 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: [ 4 | '@nuxt/eslint-config' 5 | ], 6 | rules: { 7 | // Global 8 | semi: ['error', 'never'], 9 | quotes: ['error', 'single'], 10 | 'quote-props': ['error', 'as-needed'], 11 | // Vue 12 | 'vue/multi-word-component-names': 0, 13 | 'vue/max-attributes-per-line': 'off', 14 | 'vue/no-v-html': 0 15 | } 16 | } -------------------------------------------------------------------------------- /.github/workflows/build-test.yml: -------------------------------------------------------------------------------- 1 | name: Deploy to GitHub Pages 2 | on: 3 | workflow_dispatch: 4 | push: 5 | branches: 6 | - fix-corepack-build 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v3 12 | - run: corepack enable 13 | - uses: actions/setup-node@v3 14 | with: 15 | node-version: "20" 16 | # Pick your own package manager and build script 17 | - run: pnpm install 18 | - run: pnpm build --preset github_pages 19 | - name: Upload artifact 20 | uses: actions/upload-pages-artifact@v1 21 | with: 22 | path: ./.output/public -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | # https://github.com/actions/deploy-pages#usage 2 | name: Deploy to GitHub Pages 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - main 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v3 13 | - run: corepack enable 14 | - uses: actions/setup-node@v3 15 | with: 16 | node-version: "20" 17 | # Pick your own package manager and build script 18 | - run: pnpm install 19 | - run: pnpm build --preset github_pages 20 | - name: Upload artifact 21 | uses: actions/upload-pages-artifact@v1 22 | with: 23 | path: ./.output/public 24 | # Deployment job 25 | deploy: 26 | # Add a dependency to the build job 27 | needs: build 28 | # Grant GITHUB_TOKEN the permissions required to make a Pages deployment 29 | permissions: 30 | pages: write # to deploy to Pages 31 | id-token: write # to verify the deployment originates from an appropriate source 32 | # Deploy to the github_pages environment 33 | environment: 34 | name: github_pages 35 | url: ${{ steps.deployment.outputs.page_url }} 36 | # Specify runner + deployment step 37 | runs-on: ubuntu-latest 38 | steps: 39 | - name: Deploy to GitHub Pages 40 | id: deployment 41 | uses: actions/deploy-pages@v1 42 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Nuxt dev/build outputs 2 | .output 3 | .data 4 | .nuxt 5 | .nitro 6 | .cache 7 | dist 8 | 9 | # Node dependencies 10 | node_modules 11 | 12 | # Logs 13 | logs 14 | *.log 15 | 16 | # Misc 17 | .DS_Store 18 | .fleet 19 | .idea 20 | 21 | # Local env files 22 | .env 23 | .env.* 24 | !.env.example 25 | 26 | # VSC 27 | .history 28 | package-lock.json 29 | 30 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | shamefully-hoist=true 2 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 18 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # View the Site 2 | 👉 See the live documentation site at https://docs.postalserver.io 3 | 4 | # Postal Server Documentation 5 | 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. 6 | 7 | ## The Purpose of This Repository 8 | 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 →](https://github.com/postalserver/postal) 9 | 10 | ## Contribution Instructions 11 | Contributions are welcome! Please open up a pull request that clearly describes your intentions. 12 | 13 | This site runs on [Nuxt Content](https://content.nuxtjs.org/). Please review their documentation to understand how this framework works. 14 | 15 | # Local Development Setup 16 | Follow these steps to get the site running on your local machine. 17 | 18 | ### Prerequisites 19 | - Node 18 or newer 20 | - [PNPM installed](https://pnpm.io/installation) for package management. 21 | 22 | We advise you to use [NVM](https://github.com/nvm-sh/nvm) to manage node versions and enable PNPM using corepack. 23 | 24 |
25 | NVM Setup 26 | 27 | **Change to the project directory** 28 | ```bash 29 | cd /path/to/postal-docs 30 | ``` 31 | 32 | **Install the correct Node version** 33 | ```bash 34 | nvm install 35 | ``` 36 | 37 | **Use the correct Node version** 38 | ```bash 39 | nvm use 40 | ``` 41 | 42 | 43 |
44 | 45 | 46 |
47 | 48 | Enable PNPM 49 | 50 | ### Corepack 51 | 52 | PNPM is available by default; you just need to enable corepack. 53 | 54 | ```bash 55 | corepack enable pnpm 56 | ``` 57 | 58 |
59 | 60 | 61 | 62 | 63 | ### Prepare Your System 64 | 65 | 66 | **Change to the project directory** 67 | ```bash 68 | cd /path/to/postal-docs 69 | ``` 70 | ### Install Dependencies 71 | Install the Node dependencies using PNPM. 72 | ```bash 73 | pnpm install 74 | ``` 75 | ### Start the Development Web Server 76 | Start the development server on http://localhost:3000 77 | 78 | > [!NOTE] 79 | > If you see a warning about a "Missing `NUXT_UI_PRO_LICENSE`", you can ignore that message. This is only used in production. 80 | 81 | ```bash 82 | pnpm dev 83 | ``` 84 | 85 | 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. 86 | 87 | ## How to Edit the Docs Content? 88 | This documentation uses [Nuxt Content](https://content.nuxtjs.org/) and works on the following key concepts: 89 | - Content is stored as markdown files in the `/content` folder. 90 | - Pages are sorted by the number at the beginning of their MD file. 91 | - Pages need to have a title and description as their metadata. 92 | - You can use any Nuxt UI and [Nuxt UI Pro prose component](https://ui.nuxt.com/pro/prose/callout). 93 | 94 | 95 | #### Example: 96 | ``` 97 | --- 98 | title: Feature List 99 | description: 'This is a list of features (in no particular order) of things that Postal can do.' 100 | --- 101 | 102 | # Feature List 103 | Here you can write your content. 104 | ... -------------------------------------------------------------------------------- /app.config.ts: -------------------------------------------------------------------------------- 1 | export default defineAppConfig({ 2 | ui: { 3 | primary: "orange", 4 | gray: "slate", 5 | footer: { 6 | bottom: { 7 | left: "text-sm text-gray-500 dark:text-gray-400", 8 | wrapper: "border-t border-gray-200 dark:border-gray-800", 9 | }, 10 | }, 11 | }, 12 | seo: { 13 | siteName: "Postal - the open source mail delivery platform", 14 | }, 15 | header: { 16 | logo: { 17 | alt: "Postal", 18 | light: "/logo-light.svg", 19 | dark: "/logo-dark.svg", 20 | }, 21 | search: true, 22 | links: [ 23 | { 24 | label: "Docs", 25 | to: "/docs", 26 | icon: "i-heroicons-book-open-solid", 27 | "aria-label": "Docs", 28 | }, 29 | { 30 | label: "Code", 31 | icon: "i-simple-icons-github", 32 | to: "https://github.com/postalserver", 33 | target: "_blank", 34 | "aria-label": "Postal on GitHub", 35 | }, 36 | 37 | 38 | ], 39 | }, 40 | footer: { 41 | credits: { 42 | label: "Built with Nuxt UI Pro", 43 | to: "https://ui.nuxt.com/pro", 44 | }, 45 | colorMode: true, 46 | links: [ 47 | { 48 | icon: "i-simple-icons-discord", 49 | to: "https://discord.postalserver.io", 50 | target: "_blank", 51 | "aria-label": "Postal on Discord", 52 | }, 53 | { 54 | icon: "i-simple-icons-x", 55 | to: "https://x.com/postalserverio", 56 | target: "_blank", 57 | "aria-label": "Postal on X", 58 | }, 59 | { 60 | icon: "i-simple-icons-github", 61 | to: "https://github.com/postalserver/postal", 62 | target: "_blank", 63 | "aria-label": "Postal on GitHub", 64 | }, 65 | ], 66 | }, 67 | toc: { 68 | title: "Table of Contents", 69 | 70 | bottom: { 71 | title: "Community", 72 | edit: "https://github.com/postalserver/docs/tree/main/content", 73 | links: [ 74 | { 75 | icon: "i-heroicons-star", 76 | label: "Star on GitHub", 77 | to: "https://github.com/postalserver", 78 | target: "_blank", 79 | }, 80 | { 81 | icon: "i-heroicons-chat-bubble-left-right", 82 | label: "Ask a question", 83 | to: "https://github.com/postalserver/postal/discussions", 84 | target: "_blank", 85 | } 86 | ], 87 | }, 88 | }, 89 | }); 90 | -------------------------------------------------------------------------------- /app.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 51 | -------------------------------------------------------------------------------- /components/Footer.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 24 | -------------------------------------------------------------------------------- /components/Header.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 43 | -------------------------------------------------------------------------------- /components/OgImage/OgImageDocs.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 30 | -------------------------------------------------------------------------------- /content/1.welcome/1.feature-list.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Feature List 3 | description: 'This is a list of features (in no real particular order) of things that Postal can do.' 4 | 5 | --- 6 | 7 | ### General features: 8 | - Support for multiple organizations with mail servers and users within. 9 | - Graphs and stats showing volume of incoming and outgoing mail. 10 | - Access to view historical messages. 11 | - Access to view the full outgoing and incoming message queue. 12 | - Set up webhooks to receive live information about delivery information in realtime. Full access to the last 7 days of webhook requests are also stored for debugging purposes. 13 | - Built-in DNS checking and monitoring to ensure domains you send mail from are configured correctly for maximum deliverability. 14 | - Per server retention configuration to set how long messages should be kept in the database and the maximum size to keep on disk. 15 | - Complete logging so delivery issues can easily be identified. 16 | - Mail server wide search tools to find messages that need investigation. 17 | ### Outgoing e-mails: 18 | - Send messages to the SMTP server or using the HTTP API. 19 | - Manage multiple credentials per server. 20 | - Support for DKIM signing of outbound messages. 21 | - Enable development to hold messages in Postal without actually delivering them to recipients (message can be viewed in the Postal interface). 22 | - Built-in suppression list to avoid sending mail to recipients that don't exist or can't accept e-mail. 23 | - Click and open tracking to keep track of when recipients open your e-mails and click links within them. 24 | - Configure per-server send limits to avoid abuse on mail servers. 25 | - Management of multiple pools of sending IP addresses. 26 | - Configure different senders or recipients to have mail delivered from certain IP addresses. 27 | - Mail tagging so certain e-mails can be given a tag to allow them to be grouped when needed. For example, you may tag `receipts` or `password-reset` e-mails as such. 28 | ### Incoming e-mails: 29 | - Ability to forward incoming e-mail to HTTP endpoints. 30 | - Ability to forward incoming e-mail to other SMTP servers. 31 | - Ability to forward incoming e-mail to other e-mail addresses. 32 | - Spam & thread checking with SpamAssassin and ClamAV with configurable thresholds and different methods for dealing with spam messages. 33 | 34 | This is a list of features (in no real particular order) of things that Postal can do. 35 | -------------------------------------------------------------------------------- /content/1.welcome/2.faqs.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: FAQs 3 | description: '' 4 | 5 | --- 6 | This hasn't been around long enough for anyone to have asked any question frequently enough for it to be considered an FAQ. We will update this page as soon as we have some questions to answer. 7 | 8 | ## Should I use this instead of [cloud provider]? 9 | 10 | That's really up to you. There are advantages and disadvantages of both solutions and you should pick the one that suits each individual situation. Don't take running your own e-mail platform lightly though, there are many considerations that need to be taken into account to ensure you achieve good deliverability (including correct DNS configuration). 11 | 12 | ## E-Mails sent through Postal are going to spam. 13 | 14 | * Check you've configured your DNS correctly. To start you need reverse DNS for your IPs, you need to configure DKIM & SPF, you need to make sure your rDNS matches the HELO given to the recipient's mail server. 15 | * Ensure your sending IPs have reverse DNS (PTR) records configured. 16 | * Check that the IP address you're sending mail from isn't on any blacklists. 17 | * Check that your actual e-mail doesn't look like spam. 18 | * New IPs sending large volumes of e-mail will likely not deliver well initially. 19 | 20 | You can run your message through something like [Mail Tester](https://www.mail-tester.com) which will give you a good idea of the spammy-ness of your messages and ensure you have everything configured correctly. 21 | 22 | ## Can you add [mailing list feature]? 23 | 24 | No. Postal is a mail transport agent and not a mailing list manager. We don't want to add features that are better suited in another application, for example, address books or handling the un-subscription of people from a database. 25 | -------------------------------------------------------------------------------- /content/1.welcome/_dir.yml: -------------------------------------------------------------------------------- 1 | title: Welcome -------------------------------------------------------------------------------- /content/2.getting-started/0.index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Getting Started 3 | description: '' 4 | position: 1.0 5 | category: Installation 6 | --- 7 | 8 | Postal is fairly easy to install but running your own mail server isn't something for 9 | everyone. If you use Postal, you will be responsible for configuring your DNS as well 10 | as maintaining the platform (including running upgrades). If this doesn't sound like 11 | something you're up for, try a hosted platform. 12 | 13 | The process for installing Postal is outlined below. When you're ready to get started 14 | go to the [Pre-Requisites](/getting-started/prerequisites) page. 15 | 16 | 1. Install Docker and other pre-requisites 17 | 2. Add appropriate configuration and DNS entries 18 | 3. Start Postal 19 | 4. Make your first user 20 | 5. Login to the web interface to create your first virtual mail server 21 | 22 | ## A visual learner? 23 | 24 | You can watch this video which walks through the installation process. 25 | 26 | 27 | -------------------------------------------------------------------------------- /content/2.getting-started/1.prerequisites.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Pre-requisites 3 | description: '' 4 | position: 2.0 5 | category: Installation 6 | --- 7 | 8 | There are some things you'll need to do before you can install Postal. 9 | 10 | ## Servers 11 | 12 | We **strongly** recommend installing Postal on its own dedicated server (i.e. a server running no other software). The minimum specification for Postal is as follows: 13 | 14 | * At least 4GB of RAM 15 | * At least 2 CPU cores 16 | * An appropriate amount of disk space (at least 25GB) for your use case 17 | 18 | Most people install Postal on virtual servers. There are lots of providers to choose from including [Digital Ocean](https://m.do.co/c/17696597a9ed) and [Linode](https://www.linode.com). 19 | 20 | One thing to be aware of is you'll need to ensure that your provider does not block port 25 outbound. This is quite common and is used to prevent abuse from spammers. 21 | 22 | It doesn't matter what operating system you choose as long as you are able to install Docker on it (see next section). Nothing in these instructions will make assumptions about your operating system. 23 | 24 | ## Docker 25 | 26 | Postal runs entirely using containers which means to run Postal you'll need some software to run these containers. We recommend using Docker for this purpose but you can use whatever software you wish. 27 | 28 | You'll need to install Docker Engine on your server to begin with. [Follow the instructions on the Docker website](https://docs.docker.com/engine/install/) to install Docker. 29 | 30 | You'll also need to ensure you have the [Docker Compose plugin](https://docs.docker.com/compose/install/linux/) installed. 31 | 32 | Before continuing ensure that you can run both `docker` and `docker compose` from your prompt. 33 | 34 | ## System utilities 35 | 36 | There are a few system utilities that you need to have installed before you'll be able to run some of the Postal commands. 37 | 38 | On Ubuntu/Debian: 39 | 40 | ``` 41 | apt install git curl jq 42 | ``` 43 | 44 | On CentOS/RHEL: 45 | 46 | ``` 47 | yum install git curl jq 48 | ``` 49 | 50 | ## Git & installation helper repository 51 | 52 | You'll need to make sure you have `git` installed on your server. You'll then need to clone the Postal installation helper repository. This contains some bootstrapping config and other useful things which will speed along your installation. 53 | 54 | ``` 55 | git clone https://github.com/postalserver/install /opt/postal/install 56 | sudo ln -s /opt/postal/install/bin/postal /usr/bin/postal 57 | ``` 58 | 59 | ## MariaDB (10.6 or higher) 60 | 61 | Postal requires a database engine to store all email and other essential configuration data. You will need to provide credentials that allow full access to create and delete databases as well as having full access to any databases created. Postal will provision a database automatically for each mail server that you create. 62 | 63 | We do not support using MySQL in place of MariaDB. 64 | 65 | You can run MariaDB in a container, assuming you have Docker, using this command: 66 | 67 | ``` 68 | docker run -d \ 69 | --name postal-mariadb \ 70 | -p 127.0.0.1:3306:3306 \ 71 | --restart always \ 72 | -e MARIADB_DATABASE=postal \ 73 | -e MARIADB_ROOT_PASSWORD=postal \ 74 | mariadb 75 | ``` 76 | 77 | * This will run a MariaDB instance and have it listen on port 3306. 78 | * Be sure to choose a secure password. You'll need to put this in your Postal configuration when you install it so be sure to make a (secure) note of it. 79 | * If you are unable or unwilling to grant root access, the database user you create separately needs all permissions on databases called `postal` and `postal-*` (this prefix can be configured in the `message_db` part of your configuration). 80 | 81 | ::callout{icon="i-heroicons-information-circle"} 82 | Whilst you can configure the maximum message size however you wish, you will need to verify that MariaDB is configured with innodb_log_file_size to at least 10 times the biggest message you wish to send (150MB for 15MB email, 250MB for 25MB email, etc).

If you have a legacy v1 database you might also want to check that raw tables in the database have the type LONGBLOB. 83 | :: 84 | -------------------------------------------------------------------------------- /content/2.getting-started/2.installation.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Installation 3 | description: '' 4 | position: 2.1 5 | category: Installation 6 | --- 7 | 8 | Once you've completed all the prerequisites, you can go ahead and start to install Postal. 9 | 10 | ## Configuration 11 | 12 | Before you can start Postal, you'll need some configuration. The repository you cloned includes a tool to automatically generate some initial configuration files. 13 | 14 | Run the command below and replace `postal.yourdomain.com` with the actual hostname you want to access your Postal web interface at. Make sure you have set up this domain with your DNS provider before continuing. 15 | 16 | ```bash 17 | postal bootstrap postal.yourdomain.com 18 | ``` 19 | 20 | This will generate three files in `/opt/postal/config`. 21 | 22 | * `postal.yml` is the main postal configuration file 23 | * `signing.key` is the private key used to sign various things in Postal 24 | * `Caddyfile` is the configuration for the Caddy webserver 25 | 26 | Once generated, you should open up `/opt/postal/config/postal.yml` and add all the appropriate values for your installation (database passwords etc...). 27 | 28 | ::callout{icon="i-heroicons-information-circle"} 29 | Note that the docker setup mounts /opt/postal/config as /config so any full directory paths mentioned in postal.yml will likely need to start with /config and not /opt/postal/config 30 | :: 31 | 32 | ## Initializing the database 33 | 34 | Once you've added your configuration, you need to initialize your database by adding all the appropriate tables. Run the following commands to create the schema and then create your first admin user. 35 | 36 | ```bash 37 | postal initialize 38 | postal make-user 39 | ``` 40 | 41 | ## Running postal 42 | 43 | You're now ready to actually run Postal itself. You can go ahead and do this by running: 44 | 45 | ``` 46 | postal start 47 | ``` 48 | 49 | This will run a number of containers on your machine. You can use `postal status` to see details of these components. 50 | 51 | ## Caddy 52 | 53 | To handle SSL termination and all web traffic, you'll need to configure a web proxy. You can use anything that takes your fancy here - nginx, Apache, HAProxy, anything - but in this example, we're going to use [Caddy](https://caddyserver.com). It's a great little server that requires very little configuration and is very easy to set up. 54 | 55 | ``` 56 | docker run -d \ 57 | --name postal-caddy \ 58 | --restart always \ 59 | --network host \ 60 | -v /opt/postal/config/Caddyfile:/etc/caddy/Caddyfile \ 61 | -v /opt/postal/caddy-data:/data \ 62 | caddy 63 | ``` 64 | 65 | Once this has started, Caddy will issue an SSL certificate for your domain and you'll be able to immediately access the Postal web interface and login with the user you created in one of the previous steps. 66 | 67 | ![Image](/screenshots/Screen-Shot-2021-07-29-23-26-18.23-Qwv2DD40v4jMEoaHtE.png) 68 | -------------------------------------------------------------------------------- /content/2.getting-started/3.upgrading.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Upgrading 3 | description: '' 4 | position: 2.2 5 | category: Installation 6 | --- 7 | 8 | ::callout{icon="i-heroicons-exclamation-triangle" color="amber"} 9 | If you're not currently running Postal v2, you'll need to follow the Upgrading from 1.x documentation before you can use these instructions. 10 | :: 11 | 12 | Once you have installed Postal, you can upgrade it by running this command. This will always upgrade you to the latest version of Postal that is available. 13 | 14 | ```bash 15 | cd /opt/postal/install 16 | git pull origin 17 | postal upgrade 18 | ``` 19 | 20 | This will do a few things in the following order: 21 | 22 | * Fetch the latest copy of the installation helpers repository using Git. 23 | * Pull the latest version of the Postal containers. 24 | * Perform any necessary updates to the database schema. 25 | * Restart all running containers 26 | 27 | This is not a zero downtime upgrade so it is recommended to do this at a time when traffic will be low and you have scheduled the maintenance as appropriate. If you need zero downtime upgrades, you will need to look for alternative container orchestration systems that can handle this (such as Kubernetes). 28 | 29 | ## Changing to a specific version 30 | 31 | By default, running `postal upgrade` will install the latest version available from the Postal container registry. If you need to change the version of Postal to a specific version, you can specify a version for the `postal upgrade` command as follows: 32 | 33 | ```bash 34 | postal upgrade [version] 35 | ``` 36 | -------------------------------------------------------------------------------- /content/2.getting-started/4.configuration.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Configuration 3 | description: '' 4 | category: Installation 5 | --- 6 | Postal can be configured through its configuration file or environment variables. There are a fair number of areas which can be configured. 7 | 8 | You can review all the available configuration options. 9 | 10 | * [Full Postal Configuration file](https://github.com/postalserver/postal/blob/main/doc/config/yaml.yml) - this is an example configuration file that contains all the configuration options along with their defaults and a description. This file would usually exist in `/opt/postal/config/postal.yml`. 11 | 12 | * [All environment variables](https://github.com/postalserver/postal/blob/main/doc/config/environment-variables.md) - this page lists all the environment variables. All configuration that can be set in the config file can also be set by an environment variable. 13 | 14 | ::callout 15 | Note: If you change any configuration, you should be sure to restart Postal 16 | :: 17 | 18 | ## Ports and bind addresses 19 | 20 | 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. 21 | 22 | You can use the `PORT` and `BIND_ADDRESS` environment variables to provide instance-specific values for these processes. 23 | 24 | ## Legacy configuration 25 | 26 | The current version for the Postal configuration file is `2`. This is shown by the `version: 2` in the configuration file itself. 27 | 28 | Postal still supports the version 1 (or legacy) configuration format from Postal v2 and earlier. If you are using this config file, you will receive a warning in the logs when starting Postal. We recommend changing your configuration to follow the new v2 format which is documented above. 29 | 30 | The key differences between v1 and v2 configuration is shown below. 31 | 32 | * `web.host` changes to `postal.web_hostname` 33 | * `web.protocol` changes to `postal.web_protocol` 34 | * `web_server.port` changes to `web_server.default_port` 35 | * `web_server.bind_address` changes to `web_server.default_bind_address` 36 | * `smtp_server.port` changes to `smtp_server.default_port` 37 | * `smtp_server.bind_address` changes to `smtp_server.default_bind_address` 38 | * `dns.return_path` changes to `dns.return_path_domain` 39 | * `dns.smtp_server_hostname` changes to `postal.smtp_hostname` 40 | * `general.use_ip_pools` changes to `postal.use_ip_pools` 41 | * `general.*` changes to various new names under the `postal.` namespace 42 | * `smtp_relays` changes to `postal.smtp_relays` and now uses an array of strings which should be in the format of `smtp://{host}:{port}?ssl_mode={mode}` 43 | * `logging.graylog.*` changes to `gelf.*` 44 | -------------------------------------------------------------------------------- /content/2.getting-started/4.dns-configuration.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: DNS configuration 3 | description: '' 4 | position: 2.3 5 | category: Installation 6 | --- 7 | To work properly, you'll need to configure a number of DNS records for your Postal installation. Review the table below and create appropriate DNS records with your DNS provider. You will need to enter the record names you choose in your `postal.yml` configuration file. 8 | 9 | We'll assume for the purposes of this documentation you have both IPv4 and IPv6 available to your server. We'll use the following values in this documentation, you'll need to replace them as appropriate. 10 | 11 | * `192.168.1.3` - IPv4 address 12 | * `2a00:1234:abcd:1::3` - IPv6 address 13 | * `postal.example.com` - the hostname you wish to use to run Postal 14 | 15 | ## A Records 16 | 17 | You'll need these records for accessing the API, management interface & SMTP server. 18 | 19 | 20 | 21 | 22 | 23 | 24 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
HostnameTypeValue 25 |
postal.example.comA192.168.1.3
postal.example.comAAAA2a00:1234:abcd:1::3
40 | 41 | The domain name of the email server requires an MX record pointing to `postal.example.com`. Of course, as an alternative, you can also specify some dedicated subdomains: 42 | 43 | 44 | 45 | 46 | 47 | 48 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 |
HostnameTypeValue 49 |
mx1.postal.example.comA192.168.1.3
mx1.postal.example.comAAAA2a00:1234:abcd:1::3
mx2.postal.example.comA192.168.1.3
mx2.postal.example.comAAAA2a00:1234:abcd:1::3
74 | 75 | ## SPF Record 76 | 77 | You can configure a global SPF record for your mail server which means domains don't need to each individually reference your server IPs. This allows you to make changes in the future. 78 | 79 | 80 | 81 | 82 | 83 | 84 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 |
HostnameTypeValue 85 |
spf.postal.example.comTXTv=spf1 ip4:192.168.1.3 ip6:2a00:1234:abcd:1::3 ~all
95 | 96 | ::callout{icon="i-heroicons-information-circle"} 97 | You may wish to replace ~all with -all to make the SPF record stricter. 98 | :: 99 | 100 | ## Return Path 101 | 102 | The return path domain is the default domain that is used as the `MAIL FROM` for all messages sent through a mail server. You should add DNS records as below. 103 | 104 | 105 | 106 | 107 | 108 | 109 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 |
HostnameTypeValue 110 |
rp.postal.example.comMX10 postal.example.com
rp.postal.example.comTXTv=spf1 a mx include:spf.postal.example.com ~all
postal._domainkey.rp.postal.example.comTXTValue from postal default-dkim-record
130 | 131 | 132 | ## Route domain 133 | 134 | If you wish to receive incoming e-mail by forwarding messages directly to routes in Postal, you'll need to configure a domain for this just to point to your server using an MX record. 135 | 136 | 137 | 138 | 139 | 140 | 141 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 |
HostnameTypeValue 142 |
routes.postal.example.comMX10 postal.example.com
152 | 153 | ## Click and Open Tracking 154 | 155 | If you would like to make use of Click and Open Tracking then you should set up these records however you also need to make changes to not show an error page to them. You can read more on the [Click & Open Tracking](/features/click-and-open-tracking) page. 156 | 157 | 158 | 159 | 160 | 161 | 162 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 |
HostnameTypeValue 163 |
track.postal.example.comA192.168.1.3
track.postal.example.comAAAA2a00:1234:abcd:1::3
178 | 179 | ## Example Postal Configuration 180 | 181 | In your `postal.yml` you should have something that looks like the below to cover the key DNS records. 182 | 183 | ```yaml 184 | dns: 185 | mx_records: 186 | - mx1.postal.example.com 187 | - mx2.postal.example.com 188 | spf_include: spf.postal.example.com 189 | return_path_domain: rp.postal.example.com 190 | route_domain: routes.postal.example.com 191 | track_domain: track.postal.example.com 192 | ``` 193 | -------------------------------------------------------------------------------- /content/2.getting-started/5.upgrade-to-v3.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Upgrading to v3 3 | description: "" 4 | position: 2.3 5 | category: Installation 6 | --- 7 | 8 | ::callout{color="orange" icon="i-heroicons-exclamation-circle"} 9 | If you are currently running a version of Postal less than 2.0.0, you should upgrade to v2 before v3. 10 | :: 11 | 12 | Postal v3 was released in March 2024 and introduced some changes to way that Postal runs. The noteable changes between v2 and v3 are as follows: 13 | 14 | * No need to use RabbitMQ. 15 | * No need to run `cron` or `requeuer` processes. 16 | * Improved logging. 17 | * Improve configuration management (including the ability to configure with environment variables or a config file). 18 | 19 | ## Database considerations 20 | 21 | It is important that any pre-existing tables in your database are set up with the `DYNAMIC` row format. If not, you may receive errors during the database migrations. This has been the default since MariaDB 10.2.1. 22 | 23 | You can check the format of your tables using `SHOW TABLE STATUS FROM postal`. If you have tables which are incorrect, you can change them with the following: 24 | 25 | ```sql 26 | ALTER TABLE `table_name` ROW_FORMAT=DYNAMIC; 27 | ``` 28 | 29 | ## Upgrading 30 | 31 | To upgrade, you can follow the same instructions as provided on the [upgrade page](/getting-started/upgrading) 32 | 33 | ## Configuration 34 | 35 | Postal v3 introduces a new format for its configuration file. An example of the full, new, configuration file format [can be found in our repository](https://github.com/postalserver/postal/blob/main/doc/config/yaml.yml). 36 | 37 | While v3 is still compatible with configuration from earlier versions but you should change your configuration to the new format to ensure continued compatibility. Any newly added configuration options are not available in the v1 configuration format. 38 | 39 | ## RabbitMQ 40 | 41 | Once you have upgraded to v3, you can remove any RabbitMQ services you have that solely support your Postal installation. 42 | 43 | ## Cron & Requeuer Processes 44 | 45 | These processes are not required in Postal v3 and should not be running. 46 | -------------------------------------------------------------------------------- /content/2.getting-started/6.upgrade-to-v2.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Upgrading to v2 3 | description: "" 4 | position: 2.4 5 | category: Installation 6 | --- 7 | 8 | In July 2021, we changed the way that Postal is installed. The only supported method for installing Postal is now using a container that we provide. You can follow these instructions to upgrade your 1.x installation to use containers. 9 | 10 | ## How do I know if I'm using Postal v1? 11 | 12 | There are a few changes between the two versions which should help identify your version. 13 | 14 | - The Postal web interface now has a footer on all pages (except the login page) which show the current version. If you have no footer, you're not using Postal v2. 15 | - If you installed Postal without using containers, you are most likely using Postal v1. 16 | - If you run `ps aux | grep procodile` and get any results, you are using Postal v1. 17 | - If you run `docker ps` and get no results, you are using Postal v1. 18 | - If you installed Postal before July 2021, you are using Postal v1. 19 | - If you have an `/opt/postal/app` directory you are using Postal v1 (or you have already upgraded to Postal v2 but not tidied up). 20 | 21 | ## Assumptions 22 | 23 | For the purposes of this guide, we're going to make some assumptions about your installation. If any of these assumptions are not true, you will need to determine the appropriate route for you to upgrade. 24 | 25 | - You have Postal installed on a single server. 26 | - Your server has a MariaDB (or MySQL) database server running on it and listening port 3306. 27 | - Your server has a RabbitMQ server running on it and listening on port 5672. 28 | - Your current installation is located at `/opt/postal` and your configuration is in `/opt/postal/config`. 29 | - You use a web proxy (such as nginx, Caddy or Apache) in front of the Postal web server. 30 | 31 | ::callout{icon="i-heroicons-exclamation-triangle" color="amber"} 32 | Performing this upgrade will mean that your Postal services will be unavailable for a short period of time. We recommend scheduling some maintenance and performing the upgrade when traffic is low. 33 | :: 34 | 35 | ## Preparation 36 | 37 | There are a few extra system dependencies that you need to install. 38 | 39 | - [Docker](https://docs.docker.com/get-docker/) 40 | - [docker-compose](https://docs.docker.com/compose/install/) 41 | 42 | ::callout{icon="i-heroicons-exclamation-triangle" color="amber"} 43 | Important: use the latest versions of these rather than simply just installing the latest package available from your operating system vendor's repositories. Instructions are linked above. 44 | :: 45 | 46 | If you're running an old or unsupported version of your operating system, you may wish to use this as an opportunity to upgrade. The method for doing so is outside of the scope of this documentation. 47 | 48 | ## Stopping Postal 49 | 50 | Start by stopping the Postal processes using `postal stop`. 51 | 52 | ## Configuring web proxy for open/click tracking 53 | 54 | In Postal 2.x onwards, we no longer provide a dedicated server process for serving requests for open & click tracking. If you don't use this, you can skip to the next section. However, if you do, you need to add some configuration to your web proxy and issue some SSL certificates. 55 | 56 | For all the **Tracking Domains** that you have configured (for example `track.yourdomain.com`) you will need to do the following: 57 | 58 | 1. Configure a virtual host in your web proxy to route all requests for each tracking domain to the Postal web server (on port 5000). 59 | 2. Ensure that all requests going through the proxy have the `X-Postal-Track-Host: 1` header. 60 | 3. Issue an SSL certificate for all these hosts. 61 | 4. Ensure that your web proxy is listening on the IP address that you previously used for the Postal `fast_server`. 62 | 5. As there is no longer a requirement for Postal to have two IP addresses, you can update all your DNS records that reference your secondary IP to point to the main IP that you use for Postal. 63 | 64 | ## Checking configuration 65 | 66 | Your existing configuration for Postal can remain in the same place as it was before at `/opt/postal/config`. If you have referenced any other files in your `postal.yml`, you will need to ensure that these files are within the `/opt/postal/config` folder and you replace the path with `/config`. For example, if you have this: 67 | 68 | ```yaml 69 | smtp_server: 70 | tls_enabled: true 71 | tls_certificate_path: /opt/postal/config/smtp.crt 72 | tls_private_key_path: /opt/postal/config/smtp.key 73 | ``` 74 | 75 | You will need to update `/opt/postal/config` to `/config` as follows: 76 | 77 | ```yaml 78 | smtp_server: 79 | tls_enabled: true 80 | tls_certificate_path: /config/smtp.crt 81 | tls_private_key_path: /config/smtp.key 82 | ``` 83 | 84 | ::callout{icon="i-heroicons-exclamation-triangle" color="amber"} 85 | Important: if you have referenced files in other parts of your operating system (such as in /etc), you must ensure these are now within the `/opt/postal/config` directory otherwise they won't be available within the container that Postal runs within. 86 | :: 87 | 88 | 89 | ## Removing the old Postal helper script 90 | 91 | Run the following command to backup the old Postal helper script. 92 | 93 | ``` 94 | mv /usr/bin/postal /usr/bin/postal.v1 95 | ``` 96 | 97 | ## Installing Postal v2 98 | 99 | The next thing to do is to download the new Postal installation helpers repo and set up the new `postal` command. 100 | 101 | ``` 102 | git clone https://github.com/postalserver/install /opt/postal/install 103 | sudo ln -s /opt/postal/install/bin/postal /usr/bin/postal 104 | ``` 105 | 106 | Next, run a normal upgrade using the new Postal command line helper. This will run a new image to upgrade your database schema to that required for Postal v2. 107 | 108 | ``` 109 | postal upgrade 110 | ``` 111 | 112 | Finally, you can start the Postal components. 113 | 114 | ``` 115 | postal start 116 | ``` 117 | 118 | You should now find that Postal is running again and working as normal. Confirm that all process types are running using `postal status`. Your output should look like this: 119 | 120 | ``` 121 | Name Command State Ports 122 | ------------------------------------------------------------------ 123 | postal_cron_1 /docker-entrypoint.sh post ... Up 124 | postal_requeuer_1 /docker-entrypoint.sh post ... Up 125 | postal_smtp_1 /docker-entrypoint.sh post ... Up 126 | postal_web_1 /docker-entrypoint.sh post ... Up 127 | postal_worker_1 /docker-entrypoint.sh post ... Up 128 | ``` 129 | 130 | ## A note about SMTP ports 131 | 132 | If you were previously running the Postal SMTP server on any port other than 25, you can revert this configuration and have Postal listen on this port directly. To do this, you can remove any `iptables` rules you might have and update your `postal.yml` with the new port number. 133 | 134 | ## Rolling back 135 | 136 | If something goes wrong and you need to rollback to the previous version you can still do that by reverting the `postal` helper and starting it again. 137 | 138 | ``` 139 | postal stop 140 | unlink /usr/bin/postal 141 | mv /usr/bin/postal.v1 /usr/bin/postal 142 | postal start 143 | ``` 144 | 145 | ## Tidying up 146 | 147 | When you're happy that everything is running nicely, there are some final things you should do: 148 | 149 | - Remove `/opt/postal/app`. This is where the application itself lived and is no longer required. 150 | - Remove `/opt/postal/log`. Logs are no longer stored here. 151 | - Remove `/opt/postal/vendor`. This is no longer used. 152 | - Remove the backup Postal helper tool from `/usr/bin/postal.v1`. 153 | - If you changed any tracking domains to use your main IP address, you can remove the additional IP from the server after checking that all DNS updates have applied. 154 | 155 | ## Installing on a new server with existing data 156 | 157 | If you want to simply install Postal on a new server and copy your data over, you can do so by following these instructions. 158 | 159 | 1. Create your new server and follow the instructions for installing Postal. You should have a working installation at this point. 160 | 2. On your old server, stop Postal using `postal stop`. Make sure it has fully stopped before continuing using `postal status`. 161 | 3. On your new server, stop Postal using `postal stop`. 162 | 4. Use whatever tool takes your fancy (`mysqldump`, `Mariabackup` etc...) to copy your databases to your new server. Make sure you copy the `postal` database as well as all other databases prefixed with `postal` (or whatever you have configured your prefix to be in the `message_db` part of your configuration). 163 | 5. On your new server, run `postal upgrade-db` to update the copied database with the changed table structures 164 | 6. Ensure that your `postal.yml` is merged appropriately. For example, make sure your `dns` section is correct. There is no need to copy the `rails.secret` - a new secret on the new host won't be a problem. 165 | 7. If you stopped Postal cleanly before beginning, there is no need to copy any persisted data from RabbitMQ. 166 | 8. Shutdown your old Postal server. 167 | 9. Move the IP address(es) from the old server to the new one (if both old and new servers are with the same provider). 168 | 10. Start Postal on the new server using `postal start`. 169 | -------------------------------------------------------------------------------- /content/2.getting-started/_dir.yml: -------------------------------------------------------------------------------- 1 | title: Getting Started -------------------------------------------------------------------------------- /content/3.features/_dir.yml: -------------------------------------------------------------------------------- 1 | title: Features -------------------------------------------------------------------------------- /content/3.features/click-and-open-tracking.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Click & Open Tracking 3 | description: '' 4 | category: Features 5 | --- 6 | 7 | Postal supports tracking opens and clicks from e-mails. This allows you to see when people open messages or they click links within them. 8 | 9 | 10 | 11 | 12 | ## How it works 13 | 14 | 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. 15 | 16 | ## Configuring your web server 17 | 18 | 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 `example.com`, you'll need to setup `click.example.com` (or whatever you choose) to point to your Postal server. 19 | 20 | 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. 21 | 22 | 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. 23 | 24 | If you're happy things are working, you can enable tracking as follows: 25 | 26 | 1. Find the web server you wish to enable tracking on in the Postal web interface 27 | 2. Go to the **Domains** item 28 | 3. Select **Tracking Domains** 29 | 4. Click **Add a tracking domain** 30 | 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. 31 | 32 | ## Disabling tracking on a per e-mail basis 33 | 34 | If you don't wish to track anything in an email you can add a header to your e-mails before sending it. 35 | 36 | ```text 37 | X-AMP: skip 38 | ``` 39 | 40 | ## Disabling tracking for certain link domains 41 | 42 | 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. 43 | 44 | ## Disabling tracking on a per link basis 45 | 46 | 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. 47 | 48 | * `https+notrack://postalserver.io` 49 | * `http+notrack://katapult.io/signup` 50 | -------------------------------------------------------------------------------- /content/3.features/health-metrics.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Health & Metrics 3 | description: '' 4 | category: Features 5 | --- 6 | 7 | The Postal worker and SMTP server processes come with additional functionality that allows you to monitor the health of the process as well as look at live metrics about their performance. 8 | 9 | ## Port numbers 10 | 11 | By default, the health server listens on a different port for each type of process. 12 | 13 | * Worker - listens on port `9090` 14 | * SMTP server - listens on port `9091` 15 | 16 | Unlike other services, if these ports are in use when the process starts, the health server will simply not start but the rest of the process will run as normal. This will be shown in the logs. 17 | 18 | To configure these ports you can set the `HEALTH_SERVER_PORT` and `HEALTH_SERVER_BIND_ADDRESS` environment variables. 19 | 20 | ## Metrics 21 | 22 | The metrics are exposed at `/metrics` and are in a standard Prometheus exporter format. This means they can be scraped by any tool that can ingest Prometheus metrics. This will then allow them to be turned in to graphs as appropriate. 23 | 24 | ## Health checks 25 | 26 | The `/health` endpoint will return "OK" when the process is running. This can be used for health check monitoring. 27 | -------------------------------------------------------------------------------- /content/3.features/ip-pools.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: IP Pools 3 | description: '' 4 | category: Features 5 | --- 6 | Postal supports sending messages from different IP addresses. This allows you to configure certain sets of IPs for different mail servers or send from different IPs based on the sender or recipient addresses. 7 | 8 | ## Enabling IP pools 9 | 10 | By default, IP pools are disabled and all email is sent from any IP address on the host running the workers. To use IP pools, you'll need to enable them in the configuration file. You can do this by setting the following in your `postal.yml` configuration file. You'll then need to restart Postal using `postal stop` and `postal start`. 11 | 12 | ```yaml 13 | postal: 14 | use_ip_pools: true 15 | ``` 16 | 17 | ## Configuring IP pools 18 | 19 | Once you have enabled IP pools, you'll need to set them up within the web interface. You'll see an **IP Pools** link in the top right of the interface. From here you can add pools and then add IP addresses within them. 20 | 21 | Once an IP pool has been added, you'll need to assign it any organization that should be permitted to use it. Open up the organization and choose **IPs** and then tick the pools you want to allocate. 22 | 23 | Once allocated to an organization, you can assign the IP pool to servers from the server's **Settings** page. You can also use the IP pool to configure IP rules for the organization or server. 24 | 25 | ::callout{icon="i-heroicons-exclamation-triangle" color="amber"} 26 | It's very important to make sure that the IP addresses you add in the web interface are actually configured on your Postal servers. If the IPs don't exist on the server, message delivery may fail or messages will not be dequeued correctly. 27 | :: 28 | -------------------------------------------------------------------------------- /content/3.features/logging.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Logging 3 | description: '' 4 | category: Features 5 | --- 6 | 7 | All Postal processes log to STDOUT and STDERR which means their logs are managed by whatever engine is used to run the container. In the default case, this is Docker. 8 | 9 | ## Redirecting logs to the host syslog 10 | 11 | If you want to send your log data to the host system's syslog then you can configure this. This is useful if you wish to use external tools like `fail2ban` to block users from accessing your system. 12 | 13 | The quickest way to achieve this is to use a docker compose overide file in `/opt/postal/install/docker-compose.override.yml`. The contents of this file, would contain the following: 14 | 15 | ```yaml 16 | version: "3.9" 17 | services: 18 | smtp: 19 | logging: 20 | driver: syslog 21 | options: 22 | tag: postal-smtp 23 | ``` 24 | 25 | If you wanted to put worker and web server logs there too, you can define those. The example above demonstrates using the `smtp` server process. 26 | 27 | ## Limiting the size of logs 28 | 29 | Docker cam be configured to limit the size of the log files it stores. To avoid storing large numbers of log files, you should configure this appropriately. This can be achieved by setting a maximum size in your `/etc/docker/daemon.json` file. 30 | 31 | ```json 32 | { 33 | "log-driver": "local", 34 | "log-opts": { 35 | "max-size": "100m" 36 | } 37 | } 38 | ``` 39 | 40 | ## Sending logs to Graylog 41 | 42 | Postal includes support for sending log output to a central Graylog server over UDP. This can be configured using the following options: 43 | 44 | ```yaml 45 | gelf: 46 | # GELF-capable host to send logs to 47 | host: 48 | # GELF port to send logs to 49 | port: 12201 50 | # The facility name to add to all log entries sent to GELF 51 | facility: postal 52 | ``` 53 | -------------------------------------------------------------------------------- /content/3.features/oidc.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: OpenID Connect 3 | description: '' 4 | category: Features 5 | --- 6 | 7 | Postal supports OpenID Connect (OIDC) allowing you to delegate authentication to an external service. When enabled, there are various changes: 8 | 9 | * You are not required to enter a password when you add new users. 10 | * When a user first logs in with OIDC, they will be matched to a local user based on their e-mail address. 11 | * On subsequent logins, the user will be matched based on their unique identifier provided by the OIDC issuer. 12 | * Users without local passwords cannot reset their password through Postal. 13 | * Users cannot change their local password when associated with an OIDC identity. 14 | * Existing users that currently have a password will continue to be able to use that password until it is linked with an OIDC identity. 15 | 16 | ![Screenshot](/screenshots/oidc.png) 17 | 18 | ## Configuration 19 | 20 | To get started, you'll need to find an OpenID Connect enabled provider. You should create your application within the provider in order to obtain a identifier (client ID) and a secret (client secret). 21 | 22 | You may be prompted to provide a "redirect URI" during this process. You should enter `https://postal.yourdomain.com/auth/oidc/callback`. 23 | 24 | Finally, you'll need to place your configuration in the Postal config file as normal. 25 | 26 | ```yaml 27 | oidc: 28 | # Start by enabling OIDC for your installation. 29 | enabled: true 30 | 31 | # The name of the OIDC provider as shown in the UI. For example: 32 | # "Login with My Proivder". 33 | name: My Provider 34 | 35 | # The OIDC issuer URL provided to you by your Identity provider. 36 | # The provider must support OIDC Discovery by hosting their configuration 37 | # at https://identity.example.com/.well-known/openid-configuration. 38 | issuer: https://identity.example.com 39 | 40 | # The client ID for OIDC 41 | identifier: abc1234567890 42 | 43 | # The client secret for OIDC 44 | secret: zyx0987654321 45 | 46 | # Scopes to request from the OIDC server. You'll need to find these from your 47 | # provider. You should ensure you request enough scopes to ensure the user's 48 | # email address is returned from the provider. 49 | scopes: 50 | - openid 51 | - email 52 | ``` 53 | 54 | If your Identity Provider does not support OpenID Connect discovery (which is enabled by default, you can manually configure it.) For full details of the options available see the [example config file](https://github.com/postalserver/postal/blob/main/doc/config/yaml.yml). 55 | 56 | By default, Postal will look for an email address in the `email` field and a name in the `name` field. These can be overriden using configuration if these values can be found elsewhere. 57 | 58 | ## Logging in 59 | 60 | Once enabled, you can log in by pressing the **Login with xxx** button on the login page. This will direct you to your chosen identity provider. Once authorised, you will be directed back to the application. If a user exists matching the e-mail address returned by the OpenID provider, it will be linked and you will be logged in. If not, an error will be displayed. 61 | 62 | ## Debugging 63 | 64 | Details about the user matching process will be displayed in the web server logs when the callback from the Identity provider happens. 65 | 66 | ## Disabling local authentication 67 | 68 | Once you have established your OpenID Connect set up, you can fully disable local authentication. This will change the login page as well as user management options. 69 | 70 | ```yaml 71 | oidc: 72 | # ... 73 | local_authentication_enabled: false 74 | ``` 75 | 76 | ## Using Google as an identity provider 77 | 78 | Setting up Postal to authenticate with Google is fairly straight forward. You'll need to use the Google Cloud console to generate a client ID and secret ([see docs](https://developers.google.com/identity/openid-connect/openid-connect)). When prompted for a redirect URI, you should be `https://postal.yourdomain.com/auth/oidc/callback`. The following configuration can be used to enable this: 79 | 80 | ```yaml 81 | oidc: 82 | enabled: true 83 | name: Google 84 | issuer: https://accounts.google.com 85 | identifier: # your client ID from Google 86 | secret: # your client secret from Google 87 | scopes: [openid, email] 88 | ``` 89 | -------------------------------------------------------------------------------- /content/3.features/smtp-authentication.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: SMTP Authentication 3 | description: '' 4 | category: Features 5 | --- 6 | 7 | For sending outgoing emails through the Postal SMTP server you will need to generate a credential through the Postal web interface. This credential is associated with a server and allows you to send mail from any domain associated with that domain (or the organization that owns the domain.) 8 | 9 | ## Authentication types 10 | 11 | When authenticating to the SMTP server, there are three supported authentication types. 12 | 13 | * `PLAIN` - the credentials are passed in plain text to the server. When using this, you can provide any string as the username (e.g. `x`) and the password should contain your credential string. 14 | * `LOGIN` - the credentials are passed Base64-encoded to the server. As above, you can use anything as the username and the password should contain the credential string (Base64-encoded). 15 | * `CRAM-MD5` - this is a challenge-response mechanism based on the HMAC-MD5 algorithm. Unlike the above two mechanism, the username does matter and should contain the organization and server permalinks separated by a `/` or `_` character. The password used should be the value from your credential. 16 | 17 | ## From/Sender validation 18 | 19 | When sending outgoing email through the SMTP server, it is important that the `From` header contains a domain that is owned by the server or its organization. If this it not valid, you will receive a `530 From/Sender name is not valid` error. 20 | 21 | If you have enabled "Allow Sender Header" for the server, you can include this domain in the `Sender` header instead and any value you wish in the `From` header. 22 | 23 | ## IP-based authentication 24 | 25 | Postal has the option to authenticate clients based on their IP address. To use this, you need to create an **SMTP-IP** credential for the IP or network you wish to allow to send mail. Use this carefully to avoid creating an open relay. 26 | -------------------------------------------------------------------------------- /content/3.features/smtp-tls.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: SMTP TLS 3 | description: '' 4 | category: Features 5 | --- 6 | 7 | By default, Postal's SMTP server is not TLS enabled however you can enable it by generating and providing a suitable certificate. We recommend that you use a certificate issued by a recognised certificate authority, but this isn't essential to use this feature. 8 | 9 | ## Key & certificate locations 10 | 11 | Certificates should be placed in your `/opt/postal/config` directory. 12 | 13 | * `/opt/postal/config/smtp.key` - the private key in PEM format 14 | * `/opt/postal/config/smtp.cert` - the certificate in PEM format 15 | 16 | ### Generating a self signed certificate 17 | 18 | You can use the command below to generate a self-signed certificate. 19 | 20 | ```bash 21 | openssl req -x509 -newkey rsa:4096 -keyout /opt/postal/config/smtp.key -out /opt/postal/config/smtp.cert -sha256 -days 365 -nodes 22 | ``` 23 | 24 | ## Configuration 25 | 26 | Once you have a key and certificate you will need to enable TLS in the configuration file (`/opt/postal/config/postal.yml`). Additional options are available too. 27 | 28 | ```yaml 29 | smtp_server: 30 | # ... 31 | tls_enabled: true 32 | # tls_certificate_path: other/path/to/cert/within/container 33 | # tls_private_key_path: other/path/to/cert/within/container 34 | # tls_ciphers: 35 | # ssl_version: SSLv23 36 | ``` 37 | 38 | You will need to run `postal restart` if you change the configuration or your key/certificate. 39 | -------------------------------------------------------------------------------- /content/3.features/spam-and-virus-checking.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Spam & Virus Checking 3 | description: '' 4 | category: Features 5 | --- 6 | Postal can integrate with SpamAssassin and ClamAV to automatically scan incoming and outgoing messages that pass through mail servers. 7 | 8 | ::callout{icon="i-heroicons-exclamation-triangle" color="amber"} 9 | This functionality is disabled by default. 10 | :: 11 | 12 | ## Setting up SpamAssassin 13 | 14 | By default, Postal will talk to SpamAssassin's `spamd` using an TCP socket connection (port 783). You'll need to install SpamAssassin on your server and then enable it within Postal. 15 | 16 | ### Installing SpamAssassin 17 | 18 | ``` 19 | sudo apt install spamassassin 20 | ``` 21 | 22 | #### Systemd systems 23 | On systems that use systemd (e.g. Debian Bookworm), you will need to enable the SpamAssassin timer. It is used to udpate the spam rules (which can be done manually using `sa-update`). 24 | 25 | ```shell 26 | systemctl enable --now spamassassin-maintenance.timer 27 | ``` 28 | 29 | #### Other systems 30 | On other systems, you will need to open up `/etc/default/spamassassin` and change `ENABLED` to `1` and `CRON` to `1`. On some systems (such as Ubuntu 20.04 or newer), you might need to enable the SpamAssassin daemon with the following command. 31 | 32 | ```bash 33 | update-rc.d spamassassin enable 34 | ``` 35 | 36 | Then you should restart SpamAssassin. 37 | 38 | ``` 39 | sudo systemctl restart spamassassin 40 | ``` 41 | 42 | ### Enabling in Postal 43 | 44 | To enable spam checking, you'll need to add the following to your `postal.yml` configuration file and restart. If you have installed SpamAssassin on a different host to your Postal installation you can change the host here but be sure to ensure that the `spamd` is listening on your external interfaces. 45 | 46 | ```yaml 47 | spamd: 48 | enabled: true 49 | host: 127.0.0.1 50 | port: 783 51 | ``` 52 | 53 | ``` 54 | postal stop 55 | postal start 56 | ``` 57 | 58 | ### Classifying Spam 59 | 60 | The spam system is based on a numeric scoring system and different scores are assigned to different issues which may appear in a message. You can configure different thresholds which define when a message is treated as spam. We recommend starting at 5 and updating this once you've seen how your incoming messages are classified. 61 | 62 | You have three options which can be configured on a per route basis which defines how spam messages are treated: 63 | 64 | * **Mark** - messages will be sent through to your endpoint but the spam information will be made available to you. 65 | * **Quarantine** - the message will placed into your hold queue and you'll need to release them if you wish them to be passed to your application. They will only remain here for 7 days, 66 | * **Fail** - the message will be marked as failed and will only be recorded in your message history without being sent. 67 | -------------------------------------------------------------------------------- /content/4.developer/1.api.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Using the API 3 | description: '' 4 | 5 | --- 6 | 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. 7 | 8 | [Full API documentation](https://apiv1.postalserver.io) 9 | 10 | ::callout{icon="i-heroicons-information-circle"} 11 | 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. 12 | :: 13 | 14 | ## General API Instructions 15 | 16 | * You should send POST requests to the URLs shown below. 17 | * Parameters should be encoded in the body of the request and `application/json` should be set as the `Content-Type` header. 18 | * 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. 19 | 20 | An example response body is shown below: 21 | 22 | ```javascript 23 | { 24 | "status":"success", 25 | "time":0.02, 26 | "flags":{}, 27 | "data":{"message_id":"xxxx"} 28 | } 29 | ``` 30 | 31 | 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. 32 | 33 | To authenticate a request to the API, you need to pass this key in the `X-Server-API-Key` HTTP header. 34 | 35 | ## Sending a message 36 | 37 | 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. 38 | 39 | Full details about these two methods can be found in our API documentation: 40 | 41 | * [Sending a message](https://postalserver.github.io/postal-api/controllers/send/message) 42 | * [Sending an RFC 2822 message](https://postalserver.github.io/postal-api/controllers/send/raw) 43 | 44 | 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. 45 | 46 | ```javascript 47 | { 48 | "message_id":"message-id-in-uuid-format@rp.postal.yourdomain.com", 49 | "messages":{ 50 | "john@example.com":{"id":37171, "token":"a4udnay1"}, 51 | "mary@example.com":{"id":37172, "token":"bsfhjsdfs"} 52 | } 53 | } 54 | ``` 55 | 56 | ## GET Message 57 | 58 | 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](https://postalserver.github.io/postal-api/controllers/messages/message.html). 59 | 60 | ```json 61 | { 62 | "id": 14, 63 | "_expansions": true 64 | } 65 | ``` 66 | 67 | ### Example cURL Request 68 | 69 | You can use the following cURL command to make the request: 70 | 71 | ```bash 72 | curl --location 'https:///api/v1/messages/message' \ 73 | --header 'X-Server-API-Key: $yourAPIKeyFromTheCredentialsPage' \ 74 | --header 'Content-Type: application/json' \ 75 | --data '{ 76 | "id": 14, 77 | "_expansions": true 78 | }' 79 | ``` -------------------------------------------------------------------------------- /content/4.developer/2.client-libraries.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Client Libraries 3 | description: '' 4 | 5 | --- 6 | 7 | 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. 8 | 9 | * [Ruby](https://github.com/postalserver/postal-ruby) 10 | * [Rails](https://github.com/postalserver/postal-rails) 11 | * [Ruby (mail gem)](https://github.com/postalserver/postal-mailgem) 12 | * [PHP](https://github.com/postalserver/postal-php) 13 | * [Node](https://github.com/postalserver/postal-node) 14 | * [Java](https://github.com/matthewmgamble/postal-java) 15 | * [.Net](https://github.com/KingdomFirst/PostalServer-DotNet-Framework) 16 | * [.NET Core](https://github.com/mDev86/PostalApiClient) 17 | * [Go](https://github.com/Pacerino/postal-go) 18 | * [Elixir (via Swoosh)](https://hexdocs.pm/swoosh/Swoosh.Adapters.Postal.html) 19 | * [Drupal](https://www.drupal.org/project/postal_mail) 20 | 21 | 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. 22 | 23 | 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. 24 | -------------------------------------------------------------------------------- /content/4.developer/3.http-payloads.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Receiving e-mail by HTTP 3 | description: '' 4 | 5 | --- 6 | 7 | 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. 8 | 9 | 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. 10 | 11 | * You can choose whether data is encoded as normal form data or whether Postal sends JSON as the body of the request. 12 | * You can choose whether to receive the raw message (raw) or have it as a JSON dictionary (processed). 13 | * You can choose whether you'd like replies and signatures to be separated from the plain body of the message. 14 | 15 | 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. 16 | 17 | 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. 18 | 19 | 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. 20 | 21 | You can view the attempts (along with debugging information) on the message page in the web interface. 22 | 23 | ## The processed payload 24 | 25 | When you chose to receive the message as JSON (processed), you'll receive a payload with the following attributes. 26 | 27 | ```javascript 28 | { 29 | "id":12345, 30 | "rcpt_to":"sales@awesomeapp.com", 31 | "mail_from":"test@example.com", 32 | "token":"rtmuzogUauKN", 33 | "subject":"Re: Welcome to AwesomeApp", 34 | "message_id":"81026759-68fb-4872-8c97-6dd2901cb33a@rp.postal.yourdomain.com", 35 | "timestamp":1478169798.924355, 36 | "size":"822", 37 | "spam_status":"NotSpam", 38 | "bounce":false, 39 | "received_with_ssl":false, 40 | "to":"sales@awesomeapp.com", 41 | "cc":null, 42 | "from":"John Doe ", 43 | "date":"Thu, 03 Nov 2016 10:43:18 +0000", 44 | "in_reply_to":null, 45 | "references":null, 46 | "plain_body":"Hello there!", 47 | "html_body":"

Hello there!

", 48 | "auto_submitted":"auto-reply", 49 | "attachment_quantity":1, 50 | "attachments":[ 51 | { 52 | "filename":"test.txt", 53 | "content_type":"text/plain", 54 | "size":12, 55 | "data":"SGVsbG8gd29ybGQh" 56 | } 57 | ] 58 | } 59 | ``` 60 | 61 | * You will only have the `attachments` attribute if you have enabled it. 62 | * The `data` attribute for each attachment is Base64 encoded. 63 | 64 | ## The raw message payload 65 | 66 | When you choose to receive the full message, you will receive the following attributes. 67 | 68 | ```javascript 69 | { 70 | "id":12345, 71 | "message":"REtJTS1TaWduYXR1cmU6IHY9MTsgYT1yc2Etc2hhMjU2Oy...", 72 | "base64":true, 73 | "size":859 74 | } 75 | ``` 76 | 77 | * The `base64` attribute specifies whether or not the `message` attribute is encoded with Base64. This is likely to be true all the time. 78 | -------------------------------------------------------------------------------- /content/4.developer/4.webhooks.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Webhooks 3 | description: '' 4 | 5 | --- 6 | 7 | Postal supports sending webhooks over HTTP when various events occur during the lifecycle of a message. 8 | 9 | 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. 10 | 11 | ## Message Status Events 12 | 13 | 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. 14 | 15 | * `MessageSent` - when a message is successfully delivered to a recipient/endpoint. 16 | * `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. 17 | * `MessageDeliveryFailed` - when a message cannot be delivered. 18 | * `MessageHeld` - when a message is held. 19 | 20 | ```javascript 21 | { 22 | "status":"Sent", 23 | "details":"Message sent by SMTP to aspmx.l.google.com (2a00:1450:400c:c0b::1b) (from 2a00:67a0:a:15::2)", 24 | "output":"250 2.0.0 OK 1477944899 ly2si31746747wjb.95 - gsmtp", 25 | "time":0.22, 26 | "sent_with_ssl":true, 27 | "timestamp":1477945177.12994, 28 | "message":{ 29 | "id":12345, 30 | "token":"abcdef123", 31 | "direction":"outgoing", 32 | "message_id":"5817a64332f44_4ec93ff59e79d154565eb@app34.mail", 33 | "to":"test@example.com", 34 | "from":"sales@awesomeapp.com", 35 | "subject":"Welcome to AwesomeApp", 36 | "timestamp":1477945177.12994, 37 | "spam_status":"NotSpam", 38 | "tag":"welcome" 39 | } 40 | } 41 | ``` 42 | 43 | ## Message Bounces 44 | 45 | If Postal receives a bounce message for a message that was previously accepted, you'll receive the `MessageBounced` event. 46 | 47 | ```javascript 48 | { 49 | "original_message":{ 50 | "id":12345, 51 | "token":"abcdef123", 52 | "direction":"outgoing", 53 | "message_id":"5817a64332f44_4ec93ff59e79d154565eb@app34.mail", 54 | "to":"test@example.com", 55 | "from":"sales@awesomeapp.com", 56 | "subject":"Welcome to AwesomeApp", 57 | "timestamp":1477945177.12994, 58 | "spam_status":"NotSpam", 59 | "tag":"welcome" 60 | }, 61 | "bounce":{ 62 | "id":12347, 63 | "token":"abcdef124", 64 | "direction":"incoming", 65 | "message_id":"5817a64332f44_4ec93ff59e79d154565eb@someserver.com", 66 | "to":"abcde@psrp.postal.yourdomain.com", 67 | "from":"postmaster@someserver.com", 68 | "subject":"Delivery Error", 69 | "timestamp":1477945179.12994, 70 | "spam_status":"NotSpam", 71 | "tag":null 72 | } 73 | } 74 | ``` 75 | 76 | ## Message Click Event 77 | 78 | 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. 79 | 80 | ```javascript 81 | { 82 | "url":"https://atech.media", 83 | "token":"VJzsFA0S", 84 | "ip_address":"185.22.208.2", 85 | "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", 86 | "message":{ 87 | "id":12345, 88 | "token":"abcdef123", 89 | "direction":"outgoing", 90 | "message_id":"5817a64332f44_4ec93ff59e79d154565eb@app34.mail", 91 | "to":"test@example.com", 92 | "from":"sales@awesomeapp.com", 93 | "subject":"Welcome to AwesomeApp", 94 | "timestamp":1477945177.12994, 95 | "spam_status":"NotSpam", 96 | "tag":"welcome" 97 | } 98 | } 99 | ``` 100 | 101 | ## Message Loaded/Opened Event 102 | 103 | 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.) 104 | 105 | ```javascript 106 | { 107 | "ip_address":"185.22.208.2", 108 | "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", 109 | "message":{ 110 | "id":12345, 111 | "token":"abcdef123", 112 | "direction":"outgoing", 113 | "message_id":"5817a64332f44_4ec93ff59e79d154565eb@app34.mail", 114 | "to":"test@example.com", 115 | "from":"sales@awesomeapp.com", 116 | "subject":"Welcome to AwesomeApp", 117 | "timestamp":1477945177.12994, 118 | "spam_status":"NotSpam", 119 | "tag":"welcome" 120 | } 121 | } 122 | ``` 123 | 124 | ## DNS Error Event 125 | 126 | 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. 127 | 128 | ```javascript 129 | { 130 | "domain":"example.com", 131 | "uuid":"820b47a4-4dfd-42e4-ae6a-1e5bed5a33fd", 132 | "dns_checked_at":1477945711.5502, 133 | "spf_status":"OK", 134 | "spf_error":null, 135 | "dkim_status":"Invalid", 136 | "dkim_error":"The DKIM record at example.com does not match the record we have provided. Please check it has been copied correctly.", 137 | "mx_status":"Missing", 138 | "mx_error":null, 139 | "return_path_status":"OK", 140 | "return_path_error":null, 141 | "server":{ 142 | "uuid":"54529725-8807-4069-ab29-a3746c1bbd98", 143 | "name":"AwesomeApp Mail Server", 144 | "permalink":"awesomeapp", 145 | "organization":"atech" 146 | }, 147 | } 148 | ``` 149 | -------------------------------------------------------------------------------- /content/4.developer/_dir.yml: -------------------------------------------------------------------------------- 1 | title: Developer -------------------------------------------------------------------------------- /content/5.other/1.auto-responders-and-bounces.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Auto-Responders & Bounces 3 | description: '' 4 | --- 5 | 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. 6 | 7 | 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 `abcdef@psrp.yourdomain.com`. 8 | 9 | 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. 10 | 11 | ## A note about bounces 12 | 13 | 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. 14 | -------------------------------------------------------------------------------- /content/5.other/2.containers.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Our container image 3 | description: "" 4 | --- 5 | 6 | This page contains information about how Postal actually is packaged and run within a container. 7 | 8 | ## Where's the container? 9 | 10 | Postal is packaged and hosted at `ghcr.io/postalserver/postal`. 11 | 12 | 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. 13 | 14 | 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). 15 | 16 | ## What processes need to run? 17 | 18 | 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. 19 | 20 | ### The web server 21 | 22 | - **Command:** `postal web-server` 23 | - **Ports:** 5000 24 | 25 | 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. 26 | 27 | You can run multiple web servers and load balance between them to add additional capacity for web requests. 28 | 29 | ### The SMTP server 30 | 31 | - **Command:** `postal smtp-server` 32 | - **Ports:** 25 33 | - **Capabilities required:** `NET_BIND_SERVICE` 34 | 35 | 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. 36 | 37 | You can run multiple SMTP servers and load balance between them to add additional capacity for SMTP connections. 38 | 39 | ### The worker(s) 40 | 41 | - **Command:** `postal worker` 42 | 43 | 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. 44 | 45 | ## Configuration 46 | 47 | 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). 48 | 49 | The `signing.key` can be generated using the following command: 50 | 51 | ``` 52 | openssl genrsa -out path/to/signing.key 2048 53 | ``` 54 | 55 | ## Networking 56 | 57 | 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. 58 | 59 | 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. 60 | 61 | ## Waiting for services 62 | 63 | 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. 64 | 65 | The default maximum time to wait is 30 seconds, you can override this using the `WAIT_FOR_TIMEOUT` environment variable. 66 | -------------------------------------------------------------------------------- /content/5.other/3.debugging.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Debugging 3 | description: '' 4 | 5 | --- 6 | 7 | This page contains information on how to identify problems with your installation. 8 | 9 | ## DNS 10 | 11 | Whilst Postal can verify DNS records on its own, it can be useful to check what the rest of the internet is seeing. 12 | 13 | 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`. 14 | 15 | ## SMTP 16 | 17 | 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. 18 | 19 | ### SMTP SSL 20 | 21 | 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. 22 | -------------------------------------------------------------------------------- /content/5.other/4.wildcards-and-address-tags.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Wildcards & Address Tags 3 | description: '' 4 | 5 | --- 6 | Postal supports the use of wildcards and address tags in routes. 7 | 8 | ## Using a wildcard 9 | 10 | 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. 11 | 12 | Just enter `*` in the name box to create a route for this. 13 | 14 | ## Using address tags 15 | 16 | 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+anything@yourdomain.com` without any additional configuration. 17 | -------------------------------------------------------------------------------- /content/5.other/_dir.yml: -------------------------------------------------------------------------------- 1 | title: Other Notes -------------------------------------------------------------------------------- /content/index.yml: -------------------------------------------------------------------------------- 1 | title: 'Postal - an open source mail delivery platform' 2 | description: 'A fully featured open source mail delivery platform for incoming & outgoing e-mail' 3 | features: 4 | links: 5 | - label: 'Discover more features' 6 | trailingIcon: 'i-heroicons-arrow-right-20-solid' 7 | color: 'gray' 8 | to: '/welcome/feature-list' 9 | size: lg 10 | items: 11 | - title: 'Comprehensive Web Interface' 12 | description: 'Manage your mail servers and view mail logs through an easy to user web interface.' 13 | icon: 'i-heroicons-window-20-solid' 14 | - title: 'Scalable' 15 | description: 'Easily horizontally scale your mail service up and down as needed.' 16 | icon: 'i-heroicons-arrows-pointing-out-16-solid' 17 | target: '_blank' 18 | - title: 'Webhooks' 19 | description: 'Set up webhooks to notify HTTP endpoints when messages are delivered or have issues.' 20 | icon: 'i-heroicons-envelope-open-solid' 21 | - title: 'Development Mode' 22 | description: 'Automatically hold messages in Postal as needed to handle testing during development.' 23 | icon: 'i-heroicons-adjustments-vertical-solid' 24 | - title: 'IP Pools' 25 | description: 'Send mail from different IP addresses to help build and maintain good IP reputation.' 26 | icon: 'i-heroicons-arrow-path-rounded-square-solid' 27 | - title: 'Spam & anti-virus integrations' 28 | description: 'Integrate with SpamAssassin, rspamd and ClamAV to have incoming & outgoing messages checked for threats and spam.' 29 | icon: 'i-heroicons-trash-solid' 30 | -------------------------------------------------------------------------------- /error.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 53 | -------------------------------------------------------------------------------- /layouts/docs.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 24 | -------------------------------------------------------------------------------- /nuxt.config.ts: -------------------------------------------------------------------------------- 1 | // https://nuxt.com/docs/api/configuration/nuxt-config 2 | export default defineNuxtConfig({ 3 | extends: ["@nuxt/ui-pro"], 4 | modules: [ 5 | "@nuxt/content", 6 | "@nuxt/ui", 7 | "@nuxthq/studio", 8 | "@nuxtjs/fontaine", 9 | "@nuxtjs/google-fonts", 10 | "nuxt-og-image", 11 | "@nuxthq/studio", 12 | "@nuxt/image", 13 | ], 14 | colorMode: { 15 | preference: 'dark', 16 | }, 17 | hooks: { 18 | // Define `@nuxt/ui` components as global to use them in `.md` (feel free to add those you need) 19 | "components:extend": (components) => { 20 | const globals = components.filter((c) => 21 | ["UButton", "UIcon"].includes(c.pascalName) 22 | ); 23 | 24 | globals.forEach((c) => (c.global = true)); 25 | }, 26 | }, 27 | ui: { 28 | icons: ["heroicons", "simple-icons"], 29 | }, 30 | // Fonts 31 | fontMetrics: { 32 | fonts: ["DM Sans"], 33 | }, 34 | googleFonts: { 35 | display: "swap", 36 | download: true, 37 | families: { 38 | "DM+Sans": [400, 500, 600, 700], 39 | }, 40 | }, 41 | routeRules: { 42 | "/api/search.json": { prerender: true }, 43 | "/docs": { 44 | redirect: { to: "/welcome/feature-list", statusCode: 302 }, 45 | }, 46 | "/config-v2": { 47 | redirect: { to: "/getting-started/configuration#legacy-configuration", statusCode: 301 }, 48 | }, 49 | }, 50 | devtools: { 51 | enabled: true, 52 | }, 53 | typescript: { 54 | strict: false, 55 | }, 56 | uiPro: { license: "oss" }, 57 | }); 58 | -------------------------------------------------------------------------------- /nuxt.schema.ts: -------------------------------------------------------------------------------- 1 | import { field, group } from "@nuxthq/studio/theme"; 2 | 3 | export default defineNuxtSchema({ 4 | appConfig: { 5 | ui: group({ 6 | title: "UI", 7 | description: "UI Customization.", 8 | icon: "i-mdi-palette-outline", 9 | fields: { 10 | icons: group({ 11 | title: "Icons", 12 | description: "Manage icons used in UI Pro.", 13 | icon: "i-mdi-application-settings-outline", 14 | fields: { 15 | search: field({ 16 | type: "icon", 17 | title: "Search Bar", 18 | description: "Icon to display in the search bar.", 19 | icon: "i-mdi-magnify", 20 | default: "i-heroicons-magnifying-glass-20-solid", 21 | }), 22 | dark: field({ 23 | type: "icon", 24 | title: "Dark mode", 25 | description: "Icon of color mode button for dark mode.", 26 | icon: "i-mdi-moon-waning-crescent", 27 | default: "i-heroicons-moon-20-solid", 28 | }), 29 | light: field({ 30 | type: "icon", 31 | title: "Light mode", 32 | description: "Icon of color mode button for light mode.", 33 | icon: "i-mdi-white-balance-sunny", 34 | default: "i-heroicons-sun-20-solid", 35 | }), 36 | external: field({ 37 | type: "icon", 38 | title: "External Link", 39 | description: "Icon for external link.", 40 | icon: "i-mdi-arrow-top-right", 41 | default: "i-heroicons-arrow-up-right-20-solid", 42 | }), 43 | chevron: field({ 44 | type: "icon", 45 | title: "Chevron", 46 | description: "Icon for chevron.", 47 | icon: "i-mdi-chevron-down", 48 | default: "i-heroicons-chevron-down-20-solid", 49 | }), 50 | hash: field({ 51 | type: "icon", 52 | title: "Hash", 53 | description: "Icon for hash anchors.", 54 | icon: "i-ph-hash", 55 | default: "i-heroicons-hashtag-20-solid", 56 | }), 57 | }, 58 | }), 59 | primary: field({ 60 | type: "string", 61 | title: "Primary", 62 | description: "Primary color of your UI.", 63 | icon: "i-mdi-palette-outline", 64 | default: "green", 65 | required: [ 66 | "sky", 67 | "mint", 68 | "rose", 69 | "amber", 70 | "violet", 71 | "emerald", 72 | "fuchsia", 73 | "indigo", 74 | "lime", 75 | "orange", 76 | "pink", 77 | "purple", 78 | "red", 79 | "teal", 80 | "yellow", 81 | "green", 82 | "blue", 83 | "cyan", 84 | "gray", 85 | "white", 86 | "black", 87 | ], 88 | }), 89 | gray: field({ 90 | type: "string", 91 | title: "Gray", 92 | description: "Gray color of your UI.", 93 | icon: "i-mdi-palette-outline", 94 | default: "slate", 95 | required: ["slate", "cool", "zinc", "neutral", "stone"], 96 | }), 97 | }, 98 | }), 99 | seo: group({ 100 | title: "SEO", 101 | description: "SEO configuration.", 102 | icon: "i-ph-app-window", 103 | fields: { 104 | siteName: field({ 105 | type: "string", 106 | title: "Site Name", 107 | description: 108 | "Name used in ogSiteName and used as second part of your page title (My page title - Nuxt UI Pro).", 109 | icon: "i-mdi-web", 110 | default: [], 111 | }), 112 | }, 113 | }), 114 | header: group({ 115 | title: "Header", 116 | description: "Header configuration.", 117 | icon: "i-mdi-page-layout-header", 118 | fields: { 119 | logo: group({ 120 | title: "Logo", 121 | description: "Header logo configuration.", 122 | icon: "i-mdi-image-filter-center-focus-strong-outline", 123 | fields: { 124 | light: field({ 125 | type: "media", 126 | title: "Light Mode Logo", 127 | description: "Pick an image from your gallery.", 128 | icon: "i-mdi-white-balance-sunny", 129 | default: "", 130 | }), 131 | dark: field({ 132 | type: "media", 133 | title: "Dark Mode Logo", 134 | description: "Pick an image from your gallery.", 135 | icon: "i-mdi-moon-waning-crescent", 136 | default: "", 137 | }), 138 | alt: field({ 139 | type: "string", 140 | title: "Alt", 141 | description: "Alt to display for accessibility.", 142 | icon: "i-mdi-alphabet-latin", 143 | default: "", 144 | }), 145 | }, 146 | }), 147 | search: field({ 148 | type: "boolean", 149 | title: "Search Bar", 150 | description: "Hide or display the search bar.", 151 | icon: "i-mdi-magnify", 152 | default: true, 153 | }), 154 | colorMode: field({ 155 | type: "boolean", 156 | title: "Color Mode", 157 | description: "Hide or display the color mode button in your header.", 158 | icon: "i-mdi-moon-waning-crescent", 159 | default: true, 160 | }), 161 | links: field({ 162 | type: "array", 163 | title: "Links", 164 | description: "Array of link object displayed in header.", 165 | icon: "i-mdi-link-variant", 166 | default: [], 167 | }), 168 | }, 169 | }), 170 | footer: group({ 171 | title: "Footer", 172 | description: "Footer configuration.", 173 | icon: "i-mdi-page-layout-footer", 174 | fields: { 175 | credits: group({ 176 | title: "Credits", 177 | description: "Credits configuration.", 178 | icon: "i-mdi-credit-card-outline", 179 | fields: { 180 | label: field({ 181 | type: "string", 182 | title: "Label", 183 | description: "Text to display as label of the credits.", 184 | icon: "i-mdi-format-title", 185 | default: "", 186 | }), 187 | to: field({ 188 | type: "string", 189 | title: "Link", 190 | description: "URL of the credits link.", 191 | icon: "i-mdi-link-variant", 192 | default: "", 193 | }), 194 | }, 195 | }), 196 | colorMode: field({ 197 | type: "boolean", 198 | title: "Color Mode", 199 | description: "Hide or display the color mode button in the footer.", 200 | icon: "i-mdi-moon-waning-crescent", 201 | default: false, 202 | }), 203 | links: field({ 204 | type: "array", 205 | title: "Links", 206 | description: "Array of link object displayed in footer.", 207 | icon: "i-mdi-link-variant", 208 | default: [], 209 | }), 210 | }, 211 | }), 212 | toc: group({ 213 | title: "Table of contents", 214 | description: "TOC configuration.", 215 | icon: "i-mdi-table-of-contents", 216 | fields: { 217 | title: field({ 218 | type: "string", 219 | title: "Title", 220 | description: "Text to display as title of the main toc.", 221 | icon: "i-mdi-format-title", 222 | default: "", 223 | }), 224 | bottom: group({ 225 | title: "Bottom", 226 | description: "Bottom TOC configuration.", 227 | icon: "i-mdi-table-of-contents", 228 | fields: { 229 | title: field({ 230 | type: "string", 231 | title: "Title", 232 | description: "Text to display as title of the bottom toc.", 233 | icon: "i-mdi-format-title", 234 | default: "", 235 | }), 236 | edit: field({ 237 | type: "string", 238 | title: "Edit Page Link", 239 | description: "URL of your repository content folder.", 240 | icon: "i-ph-note-pencil", 241 | default: "", 242 | }), 243 | links: field({ 244 | type: "array", 245 | title: "Links", 246 | description: "Array of link object displayed in bottom toc.", 247 | icon: "i-mdi-link-variant", 248 | default: [], 249 | }), 250 | }, 251 | }), 252 | }, 253 | }), 254 | }, 255 | }); 256 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nuxt-ui-pro-template-docs", 3 | "private": true, 4 | "type": "module", 5 | "scripts": { 6 | "build": "nuxt build", 7 | "dev": "nuxt dev", 8 | "generate": "nuxt generate", 9 | "preview": "nuxt preview", 10 | "postinstall": "nuxt prepare", 11 | "lint": "eslint .", 12 | "typecheck": "nuxt typecheck" 13 | }, 14 | "dependencies": { 15 | "@iconify-json/heroicons": "^1.1.19", 16 | "@iconify-json/simple-icons": "^1.1.90", 17 | "@nuxtjs/fontaine": "^0.4.1", 18 | "nuxt-og-image": "^2.2.4" 19 | }, 20 | "devDependencies": { 21 | "@nuxt/content": "^2.12.1", 22 | "@nuxt/eslint-config": "^0.3.13", 23 | "@nuxt/image": "^1.7.0", 24 | "@nuxt/ui-pro": "^1.2.0", 25 | "@nuxthq/studio": "^1.0.10", 26 | "@nuxtjs/google-fonts": "^3.2.0", 27 | "eslint": "^9.4.0", 28 | "nuxt": "^3.11.2", 29 | "vue-tsc": "^2.0.19" 30 | }, 31 | 32 | "packageManager": "pnpm@9.1.4" } 33 | -------------------------------------------------------------------------------- /pages/[...slug].vue: -------------------------------------------------------------------------------- 1 | 45 | 46 | 71 | -------------------------------------------------------------------------------- /pages/index.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 81 | -------------------------------------------------------------------------------- /public/CNAME.off: -------------------------------------------------------------------------------- 1 | docs.postalserver.io 2 | -------------------------------------------------------------------------------- /public/cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/postalserver/docs/c8f5b246a38aea8a1a2b551e7763c427195b2894/public/cover.png -------------------------------------------------------------------------------- /public/factory.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/postalserver/docs/c8f5b246a38aea8a1a2b551e7763c427195b2894/public/factory.jpg -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/postalserver/docs/c8f5b246a38aea8a1a2b551e7763c427195b2894/public/favicon.ico -------------------------------------------------------------------------------- /public/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/postalserver/docs/c8f5b246a38aea8a1a2b551e7763c427195b2894/public/icon.png -------------------------------------------------------------------------------- /public/logo-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | Artboard 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /public/logo-light.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | Artboard Copy 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /public/preview-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/postalserver/docs/c8f5b246a38aea8a1a2b551e7763c427195b2894/public/preview-dark.png -------------------------------------------------------------------------------- /public/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/postalserver/docs/c8f5b246a38aea8a1a2b551e7763c427195b2894/public/preview.png -------------------------------------------------------------------------------- /public/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/postalserver/docs/c8f5b246a38aea8a1a2b551e7763c427195b2894/public/screenshot.png -------------------------------------------------------------------------------- /public/screenshots.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/postalserver/docs/c8f5b246a38aea8a1a2b551e7763c427195b2894/public/screenshots.png -------------------------------------------------------------------------------- /public/screenshots/Screen-Shot-2021-07-29-23-26-18.23-Qwv2DD40v4jMEoaHtE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/postalserver/docs/c8f5b246a38aea8a1a2b551e7763c427195b2894/public/screenshots/Screen-Shot-2021-07-29-23-26-18.23-Qwv2DD40v4jMEoaHtE.png -------------------------------------------------------------------------------- /public/screenshots/oidc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/postalserver/docs/c8f5b246a38aea8a1a2b551e7763c427195b2894/public/screenshots/oidc.png -------------------------------------------------------------------------------- /public/screenshots/tracked-message.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/postalserver/docs/c8f5b246a38aea8a1a2b551e7763c427195b2894/public/screenshots/tracked-message.png -------------------------------------------------------------------------------- /public/supporters/katapult-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /public/supporters/katapult-light.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /public/supporters/krystal-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /public/supporters/krystal-light.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "@nuxtjs" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /server/api/search.json.get.ts: -------------------------------------------------------------------------------- 1 | import { serverQueryContent } from '#content/server' 2 | 3 | export default eventHandler(async (event) => { 4 | return serverQueryContent(event).where({ _type: 'markdown', navigation: { $ne: false } }).find() 5 | }) -------------------------------------------------------------------------------- /server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../.nuxt/tsconfig.server.json" 3 | } 4 | -------------------------------------------------------------------------------- /tailwind.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from 'tailwindcss' 2 | import defaultTheme from 'tailwindcss/defaultTheme' 3 | 4 | export default >{ 5 | theme: { 6 | extend: { 7 | fontFamily: { 8 | sans: ['DM Sans', 'DM Sans fallback', ...defaultTheme.fontFamily.sans] 9 | }, 10 | colors: { 11 | green: { 12 | 50: '#EFFDF5', 13 | 100: '#D9FBE8', 14 | 200: '#B3F5D1', 15 | 300: '#75EDAE', 16 | 400: '#00DC82', 17 | 500: '#00C16A', 18 | 600: '#00A155', 19 | 700: '#007F45', 20 | 800: '#016538', 21 | 900: '#0A5331', 22 | 950: '#052e16' 23 | } 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // https://nuxt.com/docs/guide/concepts/typescript 3 | "extends": "./.nuxt/tsconfig.json" 4 | } 5 | --------------------------------------------------------------------------------