正在查看旧版本。 查看 当前版本.

与当前比较 查看页面历史记录

版本 1 当前 »

简介

Maddy 是一款用 Go 语言开发的邮件服务器,部署方便,资源占用少,是一款适合个人使用的邮箱服务器。

  • 一台 VPS,支持开启 25 端口和 rDNS
  • 一个域名,支持管理 A/AAAA 记录、MX 记录、TXT 记录等
  • 邮箱域名的证书和密钥(使用 Certbot 申请)

maddy.yml

version: "3.8"
services:
  maddy:
    image: foxcpp/maddy:latest
    container_name: maddy
    ports:
      - 25:25
      - 143:143
      - 465:465
      - 993:993
    volumes:
      - /opt/docker/data/maddy:/data
      - /etc/letsencrypt/live/mail.example.com/fullchain.pem:/data/local_certs/cert.pem:ro
      - /etc/letsencrypt/live/mail.example.com/privkey.pem:/data/local_certs/key.pem:ro
    environment:
      - TZ=Asia/Shanghai
      - MADDY_HOSTNAME=mail.example.com
      - MADDY_DOMAIN=example.com

启动后开放的端口及作用

  • 25 SMTP Transfer->Exchange ClearText
  • 465 SMTPs User->Submission TLS
  • 143 IMAP Delivery->User ClearText
  • 993 IMAPs Delivery->User TLS
  • 587 ESMTP User->Submission ClearText/STARTTLS

获取 tls 证书

安装 Certbot

# Ubuntu/Debian
sudo apt-get install certbot
# Centos
sudo yum install certbot

获取 tls 证书:

sudo certbot certonly --standalone -d mail.example.com

按照提示操作,将获得证书和私钥,存储在 /etc/letsencrypt/live/mail.example.com/ 目录下。

maddy 配置

# 预设了三个变量,方便后续使用
$(hostname) = mail.example.com  # 外界通过这个域名找到你的邮件服务器
$(primary_domain) = example.com # 你的邮箱 @ 后面的域名
$(local_domains) = $(primary_domain)

# 如果要使用 nginx 反代,这里可以选择 tls off,但如此一来没法生成 dkim 密钥对
# 在之后检查时日志内会有安全警告,故推荐直接用 maddy 管理
# tls off
# tls file /etc/letsencrypt/live/$(local_domains)/fullchain.pem /etc/letsencrypt/live/$(local_domains)/privkey.pem
tls file /data/local_certs/cert.pem /data/local_certs/key.pem 

# 数据用 SQLite3 存储较为简单、轻量
auth.pass_table local_authdb {
    table sql_table {
        driver sqlite3
        dsn credentials.db
        table_name passwords
    }
}

storage.imapsql local_mailboxes {
    driver sqlite3
    dsn imapsql.db
}

# ----------------------------------------------------------------------------
# SMTP endpoints + message routing
hostname $(hostname)
table.chain local_rewrites {
    optional_step regexp "(.+)\+(.+)@(.+)" "$1@$3"
    optional_step static {
        entry postmaster postmaster@$(primary_domain)
    }
    optional_step file /data/aliases
}

msgpipeline local_routing {
    destination postmaster $(local_domains) {
        modify {
            replace_rcpt &local_rewrites
        }

        deliver_to &local_mailboxes
    }
    default_destination {
        reject 550 5.1.1 "User doesn't exist"
    }
}

# smtp 使用 25 号端口发送邮件
smtp tcp://[::]:25 {
    # tls self_signed
    limits {
        # Up to 20 msgs/sec across max. 10 SMTP connections
        all rate 20 1s
        all concurrency 10
    }
    dmarc yes
    check {
        require_mx_record
        dkim # 若无则不检查
        spf
    }
    source $(local_domains) {
        reject 501 5.1.8 "Use Submission for outgoing SMTP"
    }
    default_source {
        destination postmaster $(local_domains) {
            deliver_to &local_routing
        }
        default_destination {
            reject 550 5.1.1 "User doesn't exist"
        }
    }
}

# 如果使用 nginx 反代则这里监听到本地端口即可 tcp://127.0.0.1:587
# 不使用则邮件客户端以 SSL/TLS 方式直接访问该地址
submission tls://[::]:465 {
    limits {
        # Up to 50 msgs/sec across any amount of SMTP connections
        all rate 50 1s
    }
    auth &local_authdb
    source $(local_domains) {
        check {
            authorize_sender {
                prepare_email &local_rewrites
                user_to_email identity
            }
        }
        destination postmaster $(local_domains) {
            deliver_to &local_routing
        }
        default_destination {
            modify {
                dkim $(primary_domain) $(local_domains) default
            }
            deliver_to &remote_queue
        }
    }
    default_source {
        reject 501 5.1.8 "Non-local sender domain"
    }
}

target.remote outbound_delivery {
    limits {
        # Up to 20 msgs/sec across max. 10 SMTP connections
        # for each recipient domain.
        destination rate 20 1s
        destination concurrency 10
    }
    mx_auth {
        dane
        mtasts {
            cache fs
            fs_dir mtasts_cache/
        }
        local_policy {
            min_tls_level encrypted
            min_mx_level none
        }
    }
}

target.queue remote_queue {
    target &outbound_delivery
    autogenerated_msg_domain $(primary_domain)
    bounce {
        destination postmaster $(local_domains) {
            deliver_to &local_routing
        }
        default_destination {
            reject 550 5.0.0 "Refusing to send DSNs to non-local addresses"
        }
    }
}
# ----------------------------------------------------------------------------
# IMAP endpoints
# 同上,使用 nginx 反代则改为监听本地端口 tcp://127.0.0.1:143
imap tls://[::]:993 {
    auth &local_authdb
    storage &local_mailboxes

启动 maddy

docker compose up -d

创建 maddy 用户

# 进入容器
docker exec -it maddy /bin/sh
# 创建邮箱
maddy creds create hello@example.com
maddy imap-acct create hello@example.com

获取 DKIM 的公钥

/ # cat data/dkim_keys/*.dns
v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG...zAuhVJKPYUPTnJ3yTIzi4R2XbzfwIDAQAB
  • 无标签