from https://blog.raphaelpiccolo.com/fr/post/show/852

complete mail server with docker

the host hosting the mail server is mail.raphaelpiccolo.com

the domain is the part after the @. it means that emails will be sendable to *@raphaelpiccolo.com
compose

create this docker-compose.yml file :

mail:
  image: tvial/docker-mailserver:stable
  restart: always
  container_name: mail
  ports:
      # smtp (accept starttls) for transfer
      - "25:25"
      # esmtp (accept starttls) for submission
      - "587:587"
      # esmtp (forced encryption) for submission
      # - "465:465"
      # imap4 (accept starttls) for retrieval
      - "143:143"
      # imap4 (forced encryption) for retrieval
      - "993:993"
      # pop3 (accept starttls) for retrieval
      # - "110:110"
      # pop3 (forced encryption) for retrieval
      # - "995:995"
  cap_add:
      - NET_ADMIN
      - SYS_PTRACE
  hostname: mail.raphaelpiccolo.com
  domainname: raphaelpiccolo.com
  volumes:
      - ./mail/maildata:/var/mail
      - ./mail/mailstate:/var/mail-state
      - ./mail/maillogs:/var/log/mail
      - ./mail/config/:/tmp/docker-mailserver/
      - ./traefik/acme.json:/etc/letsencrypt/acme.json:ro
  environment:
      - "SSL_TYPE=letsencrypt"
      - "SPOOF_PROTECTION=1"

only useful to generate the https certificate used in mailserver

mailssl:
  image: containous/whoami
  container_name: mailssl
  labels:
      - traefik.enable=true
      - traefik.http.routers.mail.rule=Host(`mail.raphaelpiccolo.com`)
      - traefik.http.services.mail.loadbalancer.server.port=143
      - traefik.http.routers.mail.tls.certresolver=le
      - traefik.http.routers.mail.entrypoints=websecure
      - traefik.http.routers.mail.middlewares=securityheaders
webmail:
  image: hardware/rainloop
  restart: always
  container_name: webmail
  depends_on:
      - mail
  volumes:
      - ./webmail:/rainloop/data
  environment:
      - LOG_TO_STDOUT=true
  labels:
      - traefik.enable=true
      - traefik.http.routers.webmail.rule=Host(`webmail.raphaelpiccolo.com`)
      - traefik.http.routers.webmail.tls.certresolver=le
      - traefik.http.routers.webmail.entrypoints=websecure
      - traefik.http.routers.webmail.middlewares=securityheaders

get the setup script

curl -o setup.sh https://raw.githubusercontent.com/tomav/docker-mailserver/master/setup.sh; chmod a+x ./setup.sh

check the dns of your domain :

# the A record tells what is the ip of the server
IN A      X.X.X.X
mail IN A      X.X.X.X

# the mx record tells which server to call when you need to send emails ending like this @raphaelpiccolo.com
# they will call port 25 on this server
IN MX     10 mail.raphaelpiccolo.com.

execute this command

bash setup.sh email add contact@raphaelpiccolo.com xxx

it will create a line in the file

emacs config/postfix-accounts.cf
contact@raphaelpiccolo.com|xxxxxxxxxx

catchall address:

now every mails sent to *@raphaelpiccolo.com will be redirected to contact@raphaelpiccolo.com

emacs config/postfix-virtual.cf

@raphaelpiccolo.com contact@raphaelpiccolo.com

to test that local smtp is working and that the mailserver delivers the mails to the mailbox :

docker-compose up -d --force-recreate mail
swaks -t contact@raphaelpiccolo.com -f contact@raphaelpiccolo.com --header "Subject: foo"

will show this for success

<-  250 2.0.0 Ok: queued as EEF106F804EE

you can see the delivered mail in maildata/raphaelpiccolo.com/contact/new

you can download this mail from your phone or from a webmail.
do not send directly our mails to spam :)

run this to create keys

bash setup.sh config dkim

it will create this file containing what you should add in your dns

emacs ./config/opendkim/keys/raphaelpiccolo.com/mail.txt

then add this in dns

mail._domainkey        IN TXT    ( "v=DKIM1; h=sha256; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8XOWBJea+/0q8FOnbdWx7micDDhXv5r4dYlF6fLnA8nOzm6OAUZpppD8nXZN5SbBU9UxVRJcmBe/cVUaXbgL9vo5TxcjYpEOpx5/1nd3GsgNsPm9Ur8DhOTBN0yKSRfbRNWJXSL273jP7j/9heQI3ah4KUOh3LIjT5xCGyd3vlZTZ2/Qio" "V0xC5zckkS7HNaH3Bi655fMvlXhULM79mvw2aJAG83JfPc4ybwAPthFTIMsxyQ9sAIiEpBP2+OHscL4H42ul0MoAxrNTUW468QD5RuruKA3z5IBBngwKu7EELJQduSoQV1XfZB7rQCOMjtFCs6jpHu9Izr2CyUgBBeewIDAQAB" )

the spf record tells which server are authorized to send emails

authorise all the servers listed in mx. “~” means no problem if its another server
consider switching to “-” when everything works

IN TXT    "v=spf1 mx ~all"

dmarc record uses dkim and spf for more quality

_dmarc                 IN TXT    "v=DMARC1; p=none; rua=mailto:dmarc.report@raphaelpiccolo.com; ruf=mailto:dmarc.report@raphaelpiccolo.com; sp=none; ri=86400"

now you can restart and test

docker-compose up -d --force-recreate mail

its a webmail, it connects to the server to retrieve emails.
(you can also configure email reception directly on your phone)

use default password to first log

https://webmail.raphaelpiccolo.com/?admin
admin
12345

then change password

then add a domain : raphaelpiccolo.com

imap:
  server : mail.raphaelpiccolo.com
  port: 143
  security : starttls
smtp
  server : mail.raphaelpiccolo.com
  port: 587
  security : starttls
  use authentification

the whitelist can stay empty

if you want to add a new domain to the existing server

configure mx on new.com to point to raphaelpiccolo.com

add a new account for the new domain :

bash setup.sh email add contact@new.com xxx

generate dkim agaim

add dkim + spf + dmarc in your dns

generate the ssl certificate :
replace this line

traefik.http.routers.mail.rule=Host(`mail.raphaelpiccolo.com`)

with

traefik.http.routers.mail.rule=Host(`mail.raphaelpiccolo.com`, `mail.new.com`, )

Mails von bestimmten Absendern aus der Queue löschen

for f in $(mailq | egrep "azerb|kazak" -B1 | grep -oE "^[A-Z0-9]{10,11}" ); do postsuper -d $f; done

Mails requeuen

postsuper -r <mail-id>
  • computer/docker/mailserver.raphaelpiccolo.com.txt
  • Last modified: 2025/12/27 14:26
  • by spring