Rainloop Webmail+Maddy搭建邮件服务器

Maddy

Maddy Mail Server implements all functionality required to run a e-mail server. It can send messages via SMTP (works as MTA), accept messages via SMTP (works as MX) and store messages while providing access to them via IMAP. In addition to that it implements auxiliary protocols that are mandatory to keep email reasonably secure (DKIM, SPF, DMARC, DANE, MTA-STS). It replaces Postfix, Dovecot, OpenDKIM, OpenSPF, OpenDMARC and more with one daemon with uniform configuration and minimal maintenance cost.

Rainloop Webmail

Modest system requirements, decent performance, simple installation and upgrade,no database required - all these make RainLoop Webmail a perfect choice for your email solution.

📄准备

🔧安装docker和docker compose

这里使用docker compose来部署rainloop Webmai+Maddy,docker和docker compose安装教程省略

创建docker-compose.yml 的配置

1mkdir mail/
2cd mail/
3nano docker-compose.yml

docker-compose.yml 的配置如下:

 1services:
 2
 3  maddy:
 4    image: foxcpp/maddy:latest
 5    container_name: maddy
 6    restart: unless-stopped
 7    volumes: #mount point
 8      - ./maddy:/data 
 9      - /etc/letsencrypt/live/mail.example.com/fullchain.pem:/data/local_certs/cert.pem:ro #邮箱域名的证书挂载到docker内
10      - /etc/letsencrypt/live/mail.example.com/privkey.pem:/data/local_certs/key.pem:ro #邮箱域名的密钥挂载docker内
11    ports:
12      - 25:25/tcp
13      - 465:465/tcp
14      - 993:993/tcp
15
16  rainloop:
17    image: php:fpm-alpine3.15
18    container_name: rainloop
19    restart: unless-stopped
20    volumes:
21      - ./rainloop:/var/www/html
22    ports:
23      - 127.0.0.1:9000:9000
24    logging:
25      driver: json-file
26      options:
27        max-size: "1m"
28        max-file: "10"

🔎安装RainLoop Webmail

1cd ~/mail/
2mkdir rainloop/
3wget https://www.rainloop.net/repository/webmail/rainloop-latest.zip
4unzip rainloop-latest.zip

Nginx反代RainLoop Webmail

 1server {
 2    server_name mail.example.com;
 3    listen 443 ssl http2;
 4    listen [::]:443 ssl http2;
 5    ssl_certificate /data/certs/fullchain.pem; #邮箱域名的证书
 6    ssl_certificate_key /data/certs/cert.pem;  #邮箱域名的密钥
 7
 8    access_log  /var/log/nginx/access_mail.log;
 9    error_log   /var/log/nginx/error_mail.log;
10
11    root /data/rainloop/;
12    index  index.php;
13
14    location ~ \.php$ {
15        root           /var/www/html;
16        fastcgi_pass   127.0.0.1:9000;
17        fastcgi_index  index.php;
18        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
19        include        fastcgi_params;
20    }
21
22    location ^~ /data {
23                       deny all; #用户无法通过 Internet 直接访问rainloop目录
24    }
25}

💡配置Maddy

官方配置

1cd ~/mail/
2mkdir maddy/
3nano maddy.conf

Maddy.conf配置如下:

  1# 预设了三个变量,方便后续使用
  2$(hostname) = mail.example.com #外界通过这个域名找到你的邮件服务器。
  3$(primary_domain) = example.com #你的邮箱 @后面的域名
  4$(local_domains) = $(primary_domain)
  5
  6# 如果要使用 nginx 反代,这里可以选择 tls off,但如此一来没法生成 dkim 密钥对
  7# 在之后检查时日志内会有安全警告,故推荐直接用 maddy 管理
  8# tls off
  9#tls file /etc/letsencrypt/live/$(local_domains)/fullchain.pem /etc/letsencrypt/live/$(local_domains)/privkey.pem
 10tls file /data/local_certs/cert.pem /data/local_certs/key.pem 
 11
 12# 数据用 SQLite3 存储较为简单、轻量
 13auth.pass_table local_authdb {
 14    table sql_table {
 15        driver sqlite3
 16        dsn credentials.db
 17        table_name passwords
 18    }
 19}
 20
 21storage.imapsql local_mailboxes {
 22    driver sqlite3
 23    dsn imapsql.db
 24}
 25
 26# ----------------------------------------------------------------------------
 27# SMTP endpoints + message routing
 28
 29hostname $(hostname)
 30
 31table.chain local_rewrites {
 32    optional_step regexp "(.+)\+(.+)@(.+)" "$1@$3"
 33    optional_step static {
 34        entry postmaster postmaster@$(primary_domain)
 35    }
 36    optional_step file /data/aliases
 37}
 38
 39msgpipeline local_routing {
 40    destination postmaster $(local_domains) {
 41        modify {
 42            replace_rcpt &local_rewrites
 43        }
 44
 45        deliver_to &local_mailboxes
 46    }
 47
 48    default_destination {
 49        reject 550 5.1.1 "User doesn't exist"
 50    }
 51}
 52
 53# smtp 使用 25 号端口发送邮件
 54smtp tcp://[::]:25 {
 55    # tls self_signed
 56    limits {
 57        # Up to 20 msgs/sec across max. 10 SMTP connections.
 58        all rate 20 1s
 59        all concurrency 10
 60    }
 61
 62    dmarc yes
 63    check {
 64        require_mx_record
 65        dkim # 若无则不检查
 66        spf
 67    }
 68
 69    source $(local_domains) {
 70        reject 501 5.1.8 "Use Submission for outgoing SMTP"
 71    }
 72    default_source {
 73        destination postmaster $(local_domains) {
 74            deliver_to &local_routing
 75        }
 76        default_destination {
 77            reject 550 5.1.1 "User doesn't exist"
 78        }
 79    }
 80}
 81
 82# 如果使用 nginx 反代则这里监听到本地端口即可 tcp://127.0.0.1:587
 83# 不使用则邮件客户端以 SSL/TLS 方式直接访问该地址
 84submission tls://[::]:465 {
 85    limits {
 86        # Up to 50 msgs/sec across any amount of SMTP connections.
 87        all rate 50 1s
 88    }
 89
 90    auth &local_authdb
 91
 92    source $(local_domains) {
 93        check {
 94            authorize_sender {
 95                prepare_email &local_rewrites
 96                user_to_email identity
 97            }
 98        }
 99
100        destination postmaster $(local_domains) {
101            deliver_to &local_routing
102        }
103        default_destination {
104            modify {
105                dkim $(primary_domain) $(local_domains) default
106            }
107            deliver_to &remote_queue
108        }
109    }
110    default_source {
111        reject 501 5.1.8 "Non-local sender domain"
112    }
113}
114
115target.remote outbound_delivery {
116    limits {
117        # Up to 20 msgs/sec across max. 10 SMTP connections
118        # for each recipient domain.
119        destination rate 20 1s
120        destination concurrency 10
121    }
122    mx_auth {
123        dane
124        mtasts {
125            cache fs
126            fs_dir mtasts_cache/
127        }
128        local_policy {
129            min_tls_level encrypted
130            min_mx_level none
131        }
132    }
133}
134
135target.queue remote_queue {
136    target &outbound_delivery
137
138    autogenerated_msg_domain $(primary_domain)
139    bounce {
140        destination postmaster $(local_domains) {
141            deliver_to &local_routing
142        }
143        default_destination {
144            reject 550 5.0.0 "Refusing to send DSNs to non-local addresses"
145        }
146    }
147}
148
149# ----------------------------------------------------------------------------
150# IMAP endpoints
151# 同上,使用 nginx 反代则改为监听本地端口 tcp://127.0.0.1:143
152imap tls://[::]:993 {
153    auth &local_authdb
154    storage &local_mailboxes
155}

💻启动Maddy和Rainloop Webmail

1cd ~/mail
2docker compose upgrade -d

Maddy创建用户

1docker exec -it maddy sh
2maddy creds create [email protected] #创建邮箱
3maddy imap-acct create [email protected]

获取DKIM的公钥

1cat data/dkim_keys/*.dns

然后出现这段代码

"v=DKIM1; k=ed25519; p=nAcUUozPlhc4VPhp7hZl+owES7j7OlEv0laaDEDBAqg="

将其复制保存,将在设置DNS记录使用

设置DNS记录(域名服务商处设置)

以mail.example.com为邮件服务器的域名为例
# A 记录
mail.example.com   A     10.2.3.4
mail.example.com   AAAA  2001:beef::1

# MX 记录
example.com   MX    mail.example.com

# CNAME 记录
smtp.example.com   CNAME    mail.example.com
imap.example.com   CNAME    mail.example.com

# SPF
example.com     TXT   "v=spf1 mx ~all"

# _dmarc
_dmarc.example.com   TXT    "v=DMARC1; p=quarantine; ruf=mailto:[email protected]"

# DKIM DNS记录
default._domainkey.example.com  TXT    "v=DKIM1; k=ed25519; p=nAcUUozPlhc4VPhp7hZl+owES7j7OlEv0laaDEDBAqg="

🔋登陆Rainloop Webmail

通过邮箱域名登陆Rainloop Webmail后台控制面板

mail.example.com?admin
账号:admin
密码:12345

通过Rainloop Webmail控制面板与Maddy邮件服务器连接

  1. 点击“域名”
  2. 点击“添加域名”
  3. 输入
  • 名字:example.com
  • IMAP/SMTP服务器:mail.example.com
  • 加密:SSL/TLS
  1. 点击“添加”

登陆Rainloop Webmail

mail.example.com

测试是否能收发邮件

⚠️注意

  • 选择SSL/TLS加密,防火墙需要放行端口:465/tcp 993/tcp
  • 垃圾邮件匹配度 根据得分低问题去修改,否则发送的邮件容易进垃圾箱
  • MxtoolBox 可以查询MX记录,DKIM等用于检查是否配置正确

📦参考

使用 Hugo 构建
主题 StackJimmy 设计