How to Setup a Mail Server for Delta Chat

Delta Chat is a chat messenger which runs on e-mail. This means we can use any e-mail server to run Delta Chat accounts. One e-mail server which is easy to setup and manage, and works with Delta Chat out of the box, is Mailcow.

You can run it together with mailadm, which offers your users an easy way to create an e-mail account and directly login with Delta Chat. It is also included in this guide.

What you need:

Installing Docker

As a prerequisite you need to install docker and docker-compose.

If docker.com is Blocked:

Depending on the country where your server is in, docker.com may be blocked. You can also get docker & docker-compose from other sources, which may work:

Create DNS Entries

If you don’t have a domain yet, you can use a service like njal.la to buy a .net or .org domain for 15€ a year. You can pay with PayPal, Bitcoin, or Monero.

Let’s assume:

Now you could configure the domain settings for example.org like this:

Type Name Data TTL Priority
A mail.example.org 24.48.100.24 5min  
AAAA mail.example.org 7fe5:2f4:1ba:2381::3 5min  
MX @ mail.example.org 5min 10
CNAME autoconfig.example.org mail.example.org 5min  
CNAME autodiscover.example.org mail.example.org 5min  
CNAME mailadm.example.org mail.example.org 5min  
TXT @ “v=spf1 mx -all” 5min  
TXT _dmarc.example.org v=DMARC1;p=quarantine;rua=mailto:mailadm@example.org 5min  

You can setup the DKIM key after setting up mailcow, in System>Configuration>Options>ARC/DKIM keys.

You can do more than 5 minutes, but in case you notice something is wrong a short time helps with fixing the wrong entry.

Setup Mailcow

Set Mailcow Options

First clone the mailcow git repository - if your server doesn’t have access to github.com, you can do this step somewhere else and use scp to copy it to your server.

sudo apt install -y git
git clone https://github.com/mailcow/mailcow-dockerized
cd mailcow-dockerized

Now you should run ./generate_config.sh to generate the mailcow.conf file. If your server doesn’t have access to github.com, you first need to remove any git command from the script. Enter the options like this:

Mail server hostname (FQDN) - this is not your mail domain, but your mail servers hostname: mail.example.org
Timezone [Europe/Berlin]: UTC
Which branch of mailcow do you want to use?


Available Branches:
- master branch (stable updates) | default, recommended [1]
- nightly branch (unstable updates, testing) | not-production ready [2]
Choose the Branch with it´s number [1/2] 1

You should specify the following variables in mailcow.conf:

ADDITIONAL_SAN=mailadm.example.org
SKIP_CLAMD=y
SKIP_SOLR=y
SKIP_SOGO=y

The last 3 options remove services which are not needed for a minimal setup.

After that we need to run echo '#' > data/conf/dovecot/global_sieve_before.

Mailadm NGINX config

mailadm.example.org/new_email needs to be reachable for HTTP requests to work. So we need to create two files for Mailcows Nginx redirection. First we do echo 'mailadm.example.org' > data/conf/nginx/server_name.active and then we create the file data/conf/nginx/site.mailadm.custom and add the following block to it:

  location /new_email {
    proxy_pass http://24.48.100.24:3691/;
  }

Make sure to replace this example IP address with your server’s IP address.

This will forward all requests to mailadm.example.org/new_email to the mailadm container later.

Download mailcow containers

Now run sudo docker compose pull to download the mailcow containers. If you don’t have access to docker.com at this step, you can use an HTTP proxy.

Start Mailcow

Now start mailcow with sudo docker compose up -d.

Disabling IPv6 for mailcow

If your server doesn’t have an IPv6 address, you should disable IPv6.

Adding Domain in Mailcow

Now you can login to the mailcow web interface at https://mail.example.org. The default username is admin and the password is moohoo. You should change this password to something more secure.

The Mailcow web interface.

Next, add a domain in the web interface under “E-Mail > Configuration > Domains”. Somethings like this makes sense:

Creating a domain in mailcow

After this, you can go to “E-Mail > Configuration > Mailboxes” and create a first account. You can try it out with Delta Chat now.

In “E-Mail > Configuration > Domains”, on the right next to your domain, you can see a blue “DNS” button. It provides further recommendations for DNS entries which might help if you have problems getting your e-mails delivered to other servers.

Showing DNS settings in Mailcow

Setting up mailadm

Now we can set up mailadm - with this tool you can generate QR codes, which people can scan from Delta Chat to create an e-mail account on your server. It is probably the easiest way for users to get started with Delta Chat.

Downloading mailadm

You can use these commands to download mailadm:

cd ~
git clone https://github.com/deltachat/mailadm
cd mailadm
mkdir docker-data

Building mailadm

Now you can build the mailadm docker container with sudo docker build . -t mailadm-mailcow.

If docker.com or pypi.org is Blocked

If your server can’t reach docker.com, dl-cdn.alpinelinux.org, or pypi.org, this will fail. But you can build the docker container on a different machine and copy it to the VPS:

sudo docker build . -t mailadm-mailcow
sudo docker save -o mailadm-image.tar mailadm-mailcow
scp mailadm-image.tar example.org:
ssh example.org
sudo docker load --import mailadm-image.tar

Getting an API token from the web interface

Now you can go to https://mail.example.org/admin again, to get a mailcow API key.

You have to activate the API (Make sure to use the “Read-Write Access API” and not the “Read-Only Access API”!) and enter your server’s br-mailcow interface IP address under “Allow API access from these IPs/CIDR network notations”. You can find out the IP address with ip a show br-mailcow.

Check the checkbox “Activate API and then click on “Save Changes” and copy the API key.

Configuring mailadm

Then, in the mailadm directory, create a .env file and configure mailadm like this:

MAIL_DOMAIN=example.org
WEB_ENDPOINT=https://mailadm.example.org/new_email
MAILCOW_ENDPOINT=https://mail.example.org/api/v1/
MAILCOW_TOKEN=238473-081241-7A78B1-B7098C-E798BA

At MAILCOW_TOKEN, enter the API key which you just got from the mailcow web interface.

If you are unsure how to choose the values in .env, take a look at the documentation of mailadm.

Add mailadm alias

Now to make it easier to run mailadm commands, add this alias:

alias mailadm="$PWD/scripts/mailadm.sh"
echo "alias mailadm=$PWD/scripts/mailadm.sh" >> ~/.bashrc

Start mailadm

Then you can initialize the database and setup the bot mailadm will use to receive commands and support requests from your users:

mailadm init
mailadm setup-bot

Then you are asked to scan a QR code to join the Admin Group, a verified Delta Chat group. Anyone in the group can issue commands to mailadm via Delta Chat. You can send “/help” to the group to learn how to use it.

Now, as everything is configured, we can start the mailadm container for good:

sudo docker run -d -p 3691:3691 --mount type=bind,source=$PWD/docker-data,target=/mailadm/docker-data --name mailadm mailadm-mailcow gunicorn -b :3691 -w 1 mailadm.app:app

This starts a mailadm docker container. You can restart it with sudo docker restart mailadm, should you ever want to.

First steps with mailadm

That’s it! You can now get started with creating tokens and users with mailadm. Best look at the documentation for the first steps - it also contains hints for troubleshooting the setup if something doesn’t work.

Delta Chat uses only SMTP and IMAP, so if all of your users use Delta Chat, you can disable POP3.

To do this, add the following to mailcow.conf:

POP_PORT=127.0.0.1:110
POPS_PORT=127.0.0.1:995

Then apply the changes with sudo docker compose up -d.

By default, the nginx server also responds unencrypted on port 80. This can be bad, as some users might enter passwords over this unencrypted connection.

To prevent this, create a new file data/conf/nginx/redirect.conf and add the following server config to the file:

server {
  root /web;
  listen 80 default_server;
  listen [::]:80 default_server;
  include /etc/nginx/conf.d/server_name.active;
  if ( $request_uri ~* "%0A|%0D" ) { return 403; }
  location ^~ /.well-known/acme-challenge/ {
    allow all;
    default_type "text/plain";
  }
  location / {
    return 301 https://$host$uri$is_args$args;
  }
}

Then apply the changes with sudo docker compose restart nginx-mailcow.

Mailcow logs the IP addresses of your users for debugging purposes, so if you don’t want to keep this critical information on your server, you might want to disable logging. Note that this makes debugging of issues considerably harder. Nobody but you can guess whether this is necessary in your environment.

Mailcow keeps some logs in redis, so you can show it in the web interface - but if you add command: '--save ""' to the redis-server container in docker-compose.yml, it keeps them only in the RAM, which is hopefully not saved by a potential attacker.

To point the actual log files in /dev/null, aka Nirvana, you can:

Add the following lines to each container in mailcow-dockerized/docker-compose.yml:

      logging:
        driver: "syslog"
        options:
          syslog-address: "udp://127.0.0.1:514"
          syslog-facility: "local3"

Now you can configure rsyslog to listen on that port for log input. Uncomment the following lines in /etc/rsyslog.conf:

module(load="imudp")
input(type="imudp" port="514")

And put this in /etc/rsyslog.d/ to redirect all of that to nirvana:

local3.*        /dev/null
& stop

Finally, restart rsyslog with sudo service rsyslog restart and mailcow with sudo docker compose up -d.

Consider looking at the Mailcow logging documentation for alternatives to this configuration.

You might also create reverse DNS entries for the IPv4 and IPv6 addresses of your server, containing your domain. Reverse DNS entries improve deliverability; it helps other mail server distinguish your user’s mails from spam.

Setting rDNS entries should be possible in the hosting provider web interface. You can read more about it in this article.