banner
Moraxyc

Moraxyc's Rhapsody

Passion Forever! 永远热爱!
twitter
telegram
github
medium
discord server

自建輕量郵件伺服器?先了解傳輸原理!

電子郵件

郵件傳輸原理#

Mermaid Loading...

注:

  • 灰色部分表示對方伺服器
  • 僅供參考,有任何錯誤歡迎評論區討論!

基本定義#

  • MUA(Mail User Agent)是郵件用戶代理,也就是用戶用來發送和接收郵件的軟體。MUA 通過 IMAP 或 POP3 協議與 MRA 通信
  • MTA(Mail Transfer Agent)是郵件傳輸代理,也就是郵件伺服器上的軟體,負責通過 SMTP 協議發送和轉發郵件。MTA 會根據收信人地址中的域名查詢對應的郵件伺服器,並將郵件投遞給它
  • MDA(Mail Delivery Agent)是郵件投遞代理,也就是負責將 MTA 接收到的郵件保存到本地磁碟或指定地方的軟體。MDA 通常會進行垃圾郵件和病毒掃描,並提供郵件過濾和自動回覆等功能
  • MRA(Mail Receive Agent)是郵件接收代理,負責實現 IMAP 和 POP3 協議,與 MUA 進行互動。MRA 可以幫助用戶從郵件伺服器上下載或查看郵件
  • SMTP(Simple Mail Transfer Protocol)是一種用於電子郵件傳輸的標準協議。它定義了如何在互聯網上傳輸和傳遞電子郵件。SMTP 是一個客戶端 / 伺服器協議,它使用 TCP 作為傳輸層協議,並使用 25 端口作為默認端口,ESMTP 通過 465/587 端口
  • IMAP(Internet Message Access Protocol)是一種用於電子郵件存儲和訪問的標準協議。IMAP 協議通常使用 143/993 端口
  • POP3(Post Office Protocol version 3)是一種用於電子郵件下載的標準協議,它允許用戶通過郵件客戶端從郵件伺服器上下載郵件到本地計算機。它使用 110 端口進行傳輸,與 SMTP 協議配合使用。POP3 協議的重點在於下載,不支持在伺服器上管理郵件

常用的 MUA 有:Outlook、Apple Mail、Mutt、Fairemail

常用的 MTA 有:Sendmail、Postfix

常用的 MDA 有:procmail、dropmail、Cyrus

常用的 MRA 有:dovecot、Fetchmail、Getmail

傳輸過程#

郵件傳輸的過程可以分為以下幾個步驟:

本過程將模擬 "小明" <[email protected]>發送至 "小紅" <[email protected]>

1. 發送#

小明通過 MUA 編寫郵件,並指定[email protected],點擊發送,MUA 使用 SMTP (s) 將郵件發送到smtp.qq.com25/465/587端口

2. 傳遞#

smtp.qq.com檢查發信地址是否屬於該帳號,如果屬於,則繼續投遞。smtp.qq.com使用 DNS 查詢[email protected]對應域的 MX 記錄1。查詢成功後,將郵件轉發給gmail-smtp-in.l.google.com

3. 接收#

該過程最複雜,因為郵件發送並無驗證身份的機制,於是後續為了防止垃圾 / 釣魚 / 假冒詐騙郵件的傳遞,接收方 MTA 會進行各種檢查來確保郵件可信,MDA 也會在 MTA 確認收信後進行掃描病毒等處理過程。如果檢查未通過,重則直接退信,輕則歸入垃圾郵箱。

在接收郵件時,Gmail 會檢查 DKIM/SPF/DMARC 等記錄以及 PTR 記錄,以確保郵件的發送者是真實的、可信的,並且該郵件未被篡改。

DNSSEC
後續檢查基本基於 DNS 系統,因此
域名需支持 DNSSEC 以防記錄被篡改

具體來說,收信方 MTA 在接收郵件時,會按照以下流程進行驗證:

  1. DKIM 驗證:檢查郵件中是否包含了簽名過的 DKIM 頭部字段。如果有,Gmail 會使用公鑰對消息進行驗證,以確保該郵件是由相應域名的私鑰簽名的,防止郵件被篡改
  2. SPF 驗證:檢查郵件的發送伺服器是否在發送域名的 SPF 記錄中列出。如果不在,就會認為這封郵件可能是偽造的垃圾 / 釣魚郵件
  3. DMARC 驗證:檢查郵件是否符合發送域名的 DMARC 策略。DMARC 可以指定如何處理沒有通過 DKIM 或 SPF 驗證的郵件。例如,可以要求將這些郵件標記為垃圾郵件或拒絕投遞
  4. PTR 驗證:檢查郵件所在的 IP 地址是否與發送郵件的域名的 PTR 記錄相匹配。PTR 記錄通常用於反向 DNS 查詢,可用於驗證郵件發送方的身份

通過上述驗證,收信方 MTA 可以判斷郵件是否來自可信的發信人,並且可以有效地防止垃圾郵件、詐騙

4. 存儲#

gmail-smtp-in.l.google.com確認接收郵件後,MDA 進行處理,例如掃描 / 自動回覆等。然後將其存儲在[email protected]的郵箱中

5. 查看#

如果小紅用的是支持 Push 的 MUA (例如 Gmail 客戶端),那麼現在應該已經收到了郵件提醒,打開後即可看到小明發過來的郵件

請原諒我用小明小紅,咱就是個起名廢

自建郵件伺服器#

一般來講,現在自建郵件服如果不需要圖形化界面和其他附加功能,只需要最基本的發送、接受、阻止垃圾郵件,沒必要去使用那些過於冗雜的郵件伺服器完全解決方案,例如 iRedmail

本部分使用docker-mailserver作為例子來搭建郵件服,它包含了postfix, dovecot, SpamAssian, OpenDKIM, OpenDMARC, Fail2Ban等服務,並簡單配置為了開箱即用,基本上半小時就可以打造一個功能完備的郵件伺服器

docker-mailserver#

準備伺服器#

需要滿足幾個條件

  • ip 和伺服器域名未被列入黑名單 (可通過MX Super Tool檢查黑名單)
  • 開放 25 端口
  • 可配置 rDNS/PTR 記錄 (可選,盡量)
  • 純淨系統,安裝時將 hostname 主機名填為郵件伺服器域名,如mail.example.org

如果只是用 docker-mailserver 配置簡單的郵件服,使用人數少,那配置無需太高,1c 512m 即可

當然,要安裝 docker 及 docker-compose

配置#

如果你的郵件伺服器準備於二級域名下,如mail.example.org指向它,那將hostname配置為子域名,domainname配置為 apex 域2即可。

此處並非填寫發信域
此處僅配置郵件伺服器的所在域,例如配置為mail.example.org,那後面小節中的發信域 mx 記錄就指向它

如果直接用 apex 域,那就將hostname填為example.org,刪掉domainname

version: '3.3'
services:
  mailserver:
    image: docker.io/mailserver/docker-mailserver:latest
    container_name: mailserver
    hostname: mail
    domainname: example.org
    env_file: mailserver.env
    environment:
      - SSL_TYPE=letsencrypt
    ports:
      - "25:25"    # SMTP  (explicit TLS => STARTTLS)
      - "143:143"  # IMAP4 (explicit TLS => STARTTLS)
      - "465:465"  # ESMTP (implicit TLS)
      - "587:587"  # ESMTP (explicit TLS => STARTTLS)
      - "993:993"  # IMAP4 (implicit TLS)
    volumes:
      - ./docker-data/dms/mail-data/:/var/mail/
      - ./docker-data/dms/mail-state/:/var/mail-state/
      - ./docker-data/dms/mail-logs/:/var/log/mail/
      - ./docker-data/dms/config/:/tmp/docker-mailserver/
      - /etc/localtime:/etc/localtime:ro
      - /etc/letsencrypt:/etc/letsencrypt
    restart: always
    stop_grace_period: 1m
    cap_add:
      - NET_ADMIN
    healthcheck:
      test: "ss --listening --tcp | grep -P 'LISTEN.+:smtp' || exit 1"
      timeout: 3s
      retries: 0

環境變量#

以下是我自用的環境變量,使用前請修改所有example.org佔位符為你自己準備配置的主發信域名

還有其它一些選項可配置,請看文檔了解相關環境變量含義

強烈建議使用 certbot 申請證書!上一節的docker-compose.yml已經配置為兼容 certbot 與 letsencrypt,只需在容器外用 certbot 申請一個郵件伺服器域名的 SSL 證書即可使用

更多 SSL 配置方式請看文檔

OVERRIDE_HOSTNAME=
DMS_DEBUG=0
LOG_LEVEL=info
SUPERVISOR_LOGLEVEL=info
ONE_DIR=1
ACCOUNT_PROVISIONER=
[email protected]
ENABLE_UPDATE_CHECK=1
UPDATE_CHECK_INTERVAL=1d
PERMIT_DOCKER=none
TZ=Asia/Shanghai
NETWORK_INTERFACE=
TLS_LEVEL=
SPOOF_PROTECTION=1
ENABLE_SRS=0
ENABLE_OPENDKIM=1
ENABLE_OPENDMARC=1
ENABLE_POP3=
ENABLE_CLAMAV=0
ENABLE_RSPAMD=1
ENABLE_RSPAMD_REDIS=
ENABLE_AMAVIS=1
AMAVIS_LOGLEVEL=1
ENABLE_DNSBL=1
ENABLE_FAIL2BAN=1
FAIL2BAN_BLOCKTYPE=drop
ENABLE_MANAGESIEVE=
POSTSCREEN_ACTION=enforce
SMTP_ONLY=
SSL_TYPE=
SSL_CERT_PATH=
SSL_KEY_PATH=
SSL_ALT_CERT_PATH=
SSL_ALT_KEY_PATH=
VIRUSMAILS_DELETE_DELAY=
POSTFIX_DAGENT=
POSTFIX_MAILBOX_SIZE_LIMIT=
ENABLE_QUOTAS=1
POSTFIX_MESSAGE_SIZE_LIMIT=
CLAMAV_MESSAGE_SIZE_LIMIT=
PFLOGSUMM_TRIGGER=
PFLOGSUMM_RECIPIENT=
PFLOGSUMM_SENDER=
LOGWATCH_INTERVAL=weekly
LOGWATCH_RECIPIENT=
LOGWATCH_SENDER=
[email protected]
REPORT_SENDER=
LOGROTATE_INTERVAL=weekly
POSTFIX_INET_PROTOCOLS=all
DOVECOT_INET_PROTOCOLS=all
ENABLE_SPAMASSASSIN=1
SPAMASSASSASSIN_SPAM_TO_INBOX=1
ENABLE_SPAMASSASSASSIN_KAM=1
MOVE_SPAM_TO_JUNK=1
SA_TAG=-100000.0
SA_TAG2=5.0
SA_KILL=15.0
SA_SPAM_SUBJECT=***SPAM*****
ENABLE_FETCHMAIL=0
FETCHMAIL_POLL=300
ENABLE_LDAP=
LDAP_START_TLS=
LDAP_SERVER_HOST=
LDAP_SEARCH_BASE=
LDAP_BIND_DN=
LDAP_BIND_PW=
LDAP_QUERY_FILTER_USER=
LDAP_QUERY_FILTER_GROUP=
LDAP_QUERY_FILTER_ALIAS=
LDAP_QUERY_FILTER_DOMAIN=
DOVECOT_TLS=
DOVECOT_USER_FILTER=
DOVECOT_PASS_FILTER=
DOVECOT_MAILBOX_FORMAT=maildir
DOVECOT_AUTH_BIND=
ENABLE_POSTGREY=0
POSTGREY_DELAY=300
POSTGREY_MAX_AGE=35
POSTGREY_TEXT="Delayed by Postgrey"
POSTGREY_AUTO_WHITELIST_CLIENTS=5
ENABLE_SASLAUTHD=0
SASLAUTHD_MECHANISMS=
SASLAUTHD_MECH_OPTIONS=
SASLAUTHD_LDAP_SERVER=
SASLAUTHD_LDAP_BIND_DN=
SASLAUTHD_LDAP_PASSWORD=
SASLAUTHD_LDAP_SEARCH_BASE=
SASLAUTHD_LDAP_FILTER=
SASLAUTHD_LDAP_START_TLS=
SASLAUTHD_LDAP_TLS_CHECK_PEER=
SASLAUTHD_LDAP_TLS_CACERT_FILE=
SASLAUTHD_LDAP_TLS_CACERT_DIR=
SASLAUTHD_LDAP_PASSWORD_ATTR=
SASLAUTHD_LDAP_AUTH_METHOD=
SASLAUTHD_LDAP_MECH=
SRS_SENDER_CLASSES=envelope_sender
SRS_EXCLUDE_DOMAINS=
SRS_SECRET=
DEFAULT_RELAY_HOST=
RELAY_HOST=
RELAY_PORT=25
RELAY_USER=
RELAY_PASSWORD=

啟動 & 查看日誌#

啟動

docker-compose up -d

查看實時日誌

docker-compose logs -f

管理#

您最好的朋友!Setup.sh!

wget https://raw.githubusercontent.com/docker-mailserver/docker-mailserver/master/setup.sh
chmod a+x ./setup.sh

下載setup.sh後,可以直接運行以獲得幫助信息

由於docker-mailserver使用虛擬域,所以任何域名的配置都會在添加相關帳號後才會生成

例如使用./setup.sh email add [email protected] "<password>"後,example.org的配置和存儲位置便會生成

登錄#

選擇任何一個 MUA:

IMAP:
    host: mail.example.org
    port: 993
    encryption: tls
    username: [email protected]
    password: <password>
SMTP:
    host: mail.example.org
    port: 465
    encryption: tls
    username: [email protected]
    password: <password>

按照這樣填寫參數登錄即可

配置 dns 記錄#

接下來,請轉到你的域名服務提供商。這裡假設已經配置好郵件伺服器域名為mail.example.org,且已將 A 記錄指向伺服器。發信域名為example.org

請確保域名已配置好 DNSSEC

MX#

該記錄用於聲明為域處理郵件的伺服器

類型名稱內容優先級TTL
MX@mail.example.org101 小時

SPF#

SPF(Sender Policy Framework)用於防止郵件偽造,也就是防止垃圾郵件。可以指定哪些 IP 地址有權代表該域名發送電子郵件。

SPF 記錄語法如下:

v=spf1 a mx ip4:192.0.2.0/24 ip6:2001:0db8::/32 include:example.org ~all
  • a:該域名的 A 記錄所指向的 IP 地址允許代表該域名發信
  • mx:該域名的 MX 記錄所指向的 IP 地址允許代表該域名發信
  • ip4/ip6:允許該網段 ip 發信
  • include.com:example.com 域名的 SPF 記錄中包含的 IP 地址也可以代表該域名發送電子郵件
  • ~all:表示除了上述機制之外的所有 IP 地址都可以嘗試代表該域名發送電子郵件,但是會被標記為垃圾郵件。如果將此處改為-all,那除了前面被允許的地址外,任何地址都不可以代表該域名發信。建議使用-all

建議配置為:

類型名稱內容TTL
TXT@v=spf1 mx -all1 小時

DMARC#

DMARC(Domain-based Message Authentication, Reporting & Conformance)基於 SPF 和 DKIM,可以讓郵件接收方驗證發件人的身份,並向域名所有者提供有關發件人身份驗證結果的報告

當郵件接收方收到一封電子郵件時,它會通過 SPF 和 DKIM 技術驗證發件人的身份。如果發件人的電子郵件地址與 SPF 記錄和 DKIM 簽名匹配,則認為該郵件是合法的;否則就認為該郵件可能是垃圾郵件或欺詐郵件。如果域名所有者啟用了 DMARC,郵件接收方還會將驗證結果報告給域名所有者,以便其進一步分析和處理

DMARC 記錄語法如下:

v=DMARC1; p=quarantine; sp=none; rua=mailto:[email protected]; ruf=mailto:[email protected];
  • p: 用於指定如何處理郵件,有三種取值:none 表示只報告,不採取任何動作,quarantine 表示將郵件放入收件人的垃圾郵件文件夾中,reject 表示直接拒絕郵件。
  • sp: 用於指定子域名的處理方式,取值同 p
  • rua: 指定接收郵件驗證報告的地址,可以是多個郵箱地址,用逗號分隔。
  • ruf: 指定接收郵件處理報告地址,其它同上

建議配置為:

類型名稱內容TTL
TXT_dmarcv=DMARC1; p=quarantine; sp=quarantine; rua=mailto:[email protected]; ruf=mailto:[email protected];1 小時

DKIM#

首先,通過./setup.sh config dkim domain "<domain>"生成發信域名的 DKIM 公 / 私鑰

接著,查看docker-data/dms/config/opendkim/keys/<domain>/<selector>.txt即可找到需要發布到 DNS 的 DKIM 公鑰,形如<selector>._domainkey IN TXT ( "v=DKIM1; h=sha256; k=rsa; " "p=xxxxxxx" "xxxxxxx" "xxxxxxx" ) ; ----- DKIM key mail for example.org

使用時需去掉引號與空格,將引號內內容發布至 dns,示例如下:

類型名稱內容TTL
TXT<selector>._domainkeyv=DKIM1; h=sha256; k=rsa; p=xxxxxxxxxxxxxxxxxxxxx1 小時

高級:多域名使用#

由於使用虛擬域,docker-mailserver不存在主域名的說法,任何添加了帳號的域名都可被使用來發信,因此請謹慎添加帳號,以防發送假冒郵件被退信導致域名 /ip 進黑名單

按照上文,已經配置好example.org,該如何添加第二個test.com

只需要按照從 "使用 setup.sh 添加帳號" 這個步驟起,將發信域名全換為準備添加的第二個域名,重新走一遍流程,就可以正常發信 / 收信了

多個域名同理

優化#

PTR/rDNS#

PTR 記錄提供 IP 地址和域名之間的映射關係

在郵件傳輸過程中,郵件伺服器會根據 IP 地址來確定郵件發送方的域名。如果郵件伺服器收到了一封來自未知 IP 地址的郵件,它會嘗試使用 PTR 記錄查找該 IP 地址對應的域名。如果查找成功,並且該域名與郵件中的發件人域名匹配,那麼該郵件就被認為是合法的

例如,iCloud Mail 某一台 mx 伺服器的 ip 地址為17.42.251.62,那麼dig -x 17.42.251.62即可反查到該 ip 指向的域名

附加:解除黑名單 / 白名單#

DNSWL是一個不錯的 ip 地址庫,可以將域名與其匹配的 ip 認證為白名單

SpamHaus也可用於檢查是否為黑名單,並提供自助申訴

檢查#

Mail Tester可以非常方便地看出得分,10 分基本上就不可能被放進垃圾郵箱裡了

得瑟一下

Footnotes#

  1. 該記錄對於大型郵件服務提供商而言,一般會有多個 MTA,這只是優先級最高的那個。例如通過dig MX gmail.com可以看到 gmail 具有五個 MX 記錄alt4.gmail-smtp-in.l.google.com,gmail-smtp-in.l.google.com,alt3.gmail-smtp-in.l.google.com,alt2.gmail-smtp-in.l.google.com,alt1.gmail-smtp-in.l.google.com

  2. Apex 域是指域名中的最高層級,不包括任何子域名。例如,在www.example.org域中,example.org是 apex 域

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。