用 Postal 無痛架設 Mail Server

大約在兩週前的 Ruby Weekly 中,看到了一個名為 Postal 的開源專案。

介紹是這樣寫的:

一個可以讓你建置類似於 Mandrill 或者 SendGrid 服務的開源專案。

因為是使用 Rails 開發,再加上這幾年因為垃圾信的氾濫,所以在 Production 環境都會選擇使用像是 AWS SES 或者 SendGrid 這類服務來發信,除了不容易退信以及有完善的 SMTP / HTTP API 之外,也能夠避免被當作是垃圾信。

不過 Postal 特別的地方在於,如果有完整的設定完成的話,在垃圾信的檢測中甚至能夠比 AWS SES 這類服務獲得更高的分數。

Postal 簡介

Postal 是由一家位於英國的公司 aTech Media 所開發,用於內部的發信處理工具。使用的是 Ruby 以及 Rails 進行開發,並且具備了市面大多發信類的 SaaS 服務所提供的功能。

環境準備

為了簡化架設流程,在五倍紅寶石所進行的架設方式是採用 Docker 的方式來架設,如果要採用實體機器安裝的話,則需要以下預先安裝好的環境。

目前並沒有官方版本的 Docker Image 主要是 aTech 沒有這方面的經驗,詳細可以參考 #8 這個 Issue 來追蹤中況狀。

  • Ubuntu 16.04+ (並安裝 build-essential)
  • Ruby 2.3+
  • MySQL
  • RabbmitMQ
  • Node.js
  • Git
  • 兩組 Public IP (如果要使用 Fast Server)

大部分的套件官方都沒有指定版本,不過可以的話盡量以最新穩定版本為主會比較保險。

後面的文章會以 Docker 的方式來介紹,如果想要採用實體機器安裝的方式可以參考官方的 Wiki

啟動容器

這篇文章採用的是 ALinuxNinja/docker-postal 的版本,在開始前請先安裝好 Docker Compose 以及最新版本的 Docker。

Step1

首先,先把 Repoistory Clone 到本機。

cd /home/deploy/docker
git clone https://github.com/ALinuxNinja/docker-postal postal

Step2

因為主機上還有不少其他服務,所以要先修改 docker-compose.yml 將對應的 Post 調整,再用 Nginx 做反向代理。

version: "3"
services:
  postal:
    build: .
    image: postal
    container_name: postal
    ports:
      - 9080:5000
      - 2525:2525
      - 9180:5010
      - 9181:5011
    volumes:
      - ./data/postal:/opt/postal/config
      - ./data/docker:/docker
    environment:
      - MYSQL_ROOT_PASSWORD=changeme
      - MYSQL_DATABASE=postal
      - RABBITMQ_DEFAULT_USER=postal
      - RABBITMQ_DEFAULT_PASS=changeme
      - RABBITMQ_DEFAULT_VHOST=postal
  mysql:
    image: mariadb:10
    container_name: postal_mysql
    volumes:
      - ./data/mysql:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=changeme
      - MYSQL_DATABASE=postal
  rabbitmq:
    image: rabbitmq:3-alpine
    container_name: postal_rabbitmq
    environment:
      - RABBITMQ_DEFAULT_USER=postal
      - RABBITMQ_DEFAULT_PASS=changeme
      - RABBITMQ_DEFAULT_VHOST=/postal

資料庫的密碼請自行修改,這邊一共會用到四組 Port。

  • 5000 - Web 介面用的 Port 之後會用 Nginx 做反向代理並且加上 SSL
  • 2525 - SMTP 伺服器的 Port 之後會用 iptables 做 Forwording (也可以直接 Expose 到 25 上)
  • 5010/5011 - Fast Server 用的 Port 用來追蹤是否有開信以及點擊連結

最後兩個 Port 如果沒有要使用的話,可以直接跳過。

Step3

完成設定後先跑一次 docker-compose up 將容器建立起來,在首次運作的時候會自動將 Postal 所需的設定檔生成。

Step4

生成完畢後,我們要修改 data/postal/postal.yml 這個檔案,將 Mail Server 的相關設定都配置到定位。

web:
  # The host that the management interface will be available on
  host: mail.5xruby.tw
  # The protocol that requests to the management interface should happen on
  protocol: https

fast_server:
  # This can be enabled to enable click & open tracking on emails. It is disabled by
  # default as it requires a separate static IP address on your server.
  enabled: true

dns:
  # Specifies the DNS record that you have configured. Refer to the documentation at
  # https://github.com/atech/postal/wiki/Domains-&-DNS-Configuration for further
  # information about these.
  mx_records:
    - mx.mail.5xruby.tw
  smtp_server_hostname: smtp.5xruby.tw
  spf_include: spf.mail.5xruby.tw
  return_path: rp.mail.5xruby.tw
  route_domain: routes.mail.5xruby.tw
  track_domain: track.mail.5xruby.tw

主要需要修改的是 web fast_server dns 這三個部分,之後使用重新用 docker-compose up -d 的方式開啟伺服器,並且繼續接下來的動作。

Step5

原本我們可以直接用 postal make-user 來生成管理員,但是因為是封裝在 Docker Container 中的關係,需要稍微調整一下做法。

docker exec -it postal /opt/postal/bin/postal make-user
# 輸入管理員資訊

信箱請跟剛剛設定的 Domain 一樣,例如 example@5xruby.tw 這樣才會自動被判定成管理員,否則會被視為一般使用者,此時因為 SMTP 還沒有設定完成,所以會出現無法收到驗證碼的狀況。

Step6

接下來要設定 DNS 的紀錄,這邊假設 Public IP 是 192.168.1.3 & 192.168.0.4

mail.5xruby.tw.        IN    A    192.168.1.3
mx.mail.5xruby.tw.     IN    A     192.168.1.3
spf.mail.5xruby.tw.    TXT   "v=spf1 ip4:192.168.1.3 ~all"
rp.mail.5xruby.tw.     IN    MX    10 mx.mail.yourdomain.com
rp.mail.5xruby.tw      TXT   "v=spf1 a mx include:spf.mail.5xruby.tw ~all"
routes.mail.5xruby.tw. IN    MX    10 mx.mail.5xruby.tw
track.mail.5xruby.tw.  IN    A     192.168.0.4

以及一個 DKIM 紀錄,以往這需要自己生成,在這邊 Postal 已經做好自動處理的動作,在正確設定 postal.yml 的設定後,用下面的方式生成。

docker exec -it postal /opt/postal/bin/postal default-dkim-record

之後再補上一筆 DKIM 的紀錄到 DNS 上。

postal._domainkey.rp.mail.5xruby.tw.      IN    TXT "v-DKIM1; ...."

Step7

有了管理員帳號後,就可以到 Postal 的管理介面新增一個 Mail Server。

首先第一步是新增 Organization 來管理一系列的 Mail Server。 螢幕快照 2017-05-05 下午5.47.37.png

接下來就可以新增 Mail Server 來使用。

螢幕快照 2017-05-05 下午5.58.07.png

有了 Mail Server 之後,就可以新增 Domain。可以針對 Server 新增只能在特定 Server 上使用的 Domain 或者整個 Organization 都可以通用的 Domain。

使用的限制跟 SendGrid 等類似,只有擁有權限的狀況才能夠透過該 Domain 發信。

螢幕快照 2017-05-05 下午6.00.52.png

設定成功後就會看到綠色的標記,非常容易懂。

如果使用 CloudFlare 來管理 DNS 的話,使用 CNAME rp.mail.5xruby.tw 會直接被轉回 IP 但是目前 Postal 無法判斷,可以的話請分開設定,或者用另一個 Domain 設定預設的 Reture Path DNS

Step8

有了 Mail Server 以及正確的 Domain 設定後,我們需要給 Postal 一個可用的 Certificate 來當作系統發信用的帳號密碼。

螢幕快照 2017-05-05 下午6.02.51.png

新增完畢後,把 NameKey 複製到之前跳過的 postal.yml 設定檔中 SMTP 設定的部分。

smtp:
  host: 127.0.0.1
  port: 2525
  username: system # Complete when Postal is running and you can
  password: your_certificate_key # generate the credentials within the interface.
  from_name: Postal
  from_address: postal@yourdomain.com

設定完畢後,使用 docker-compose restart postal 重新啟動 Postal 就可以正常的發信。

Step9

完成上述設定後,可以到 Mail Tester 上面測試發信的狀況,剛設定好後大概可以得到 8.5/10 左右。

後續還有一些像是 rDNS 等設定,就需要透過網路服務商協助設定。如果是使用 AWS EC2 之類的,也可以透過提交表單進行申請。至於常見的 VPS 廠商大多會在後台提供修改設定的欄位,不過扣除掉因為運氣因素 IP 位置在黑名單中的情況,大多數時候都可以達到 8 分以上。

螢幕快照 2017-05-05 下午6.08.04.png

之前實測 AWS SES 獲得的分數大約是 8.5/10 左右,如果 IP 沒有被視為黑名單的話,達到 9/10 以上的分數,送達率基本上就非常高了。

Tracking

如果要啟用 Fast Server 來追蹤信件開啟狀況,則需要使用第二組 IP 位置來處理。

主要是因為 Nginx 正常情況下無法動態對應任意域名的 SSL 憑證,因此 Postal 直接使用 TCPSocket 模擬 HTTP 連線,直接進行處理。

iptables -t nat -I PREROUTING -d 192.128.0.4 -p tcp -m tcp --dport 80 -j DNAT --to-destination 192.128.0.4:5010
iptables -t nat -I PREROUTING -d 192.128.0.4 -p tcp -m tcp --dport 443 -j DNAT --to-destination 192.128.0.4:5011

iptables -I INPUT -p tcp -m tcp -d 192.128.0.4 --dport 5010 -j ACCEPT
iptables -I INPUT -p tcp -m tcp -d 192.128.0.4 --dport 5011 -j ACCEPT

這邊只需要透過 iptables 進行設定,將封包的流量轉換到對應的 Port 即可。

使用 Docker 可能會因為這樣處理而讓 OUTPUT 流量都被轉換,可以透過增加 -i 設定,只對對外網路的網卡轉換封包,即可避免這個問題。

完成封包轉換的設定後,還需要設定 Let’s Encrypt 負責生成憑證的帳號(信箱)這只是用來計算生成限制的,一般通常不會超過上限。

docker exec -it postal /opt/postal/bin/postal register-lets-encrypt postal@5xruby.tw

完成後可以到 Mail Server 中設定 Tracking Domain 如果 Fast Server 正常運作,則會發現 SSL 憑證呈現啟用的狀態,在未成功啟用的情況下會自動 Fallback 為普通的 HTTP 來做追蹤。

螢幕快照 2017-05-05 下午6.19.06.png

當順利追蹤之後,則可以看到 OPENED 的標記,以及在信件活動中看到開啟的紀錄。

螢幕快照 2017-05-05 下午6.20.53.png

小結

相較於以往架設 Mail Server 的經驗,使用 Postal 的難度相對地減少非常多。在更新以及後續升級上也相當容易,不過目前還在不穩定的狀態,還有很多預想外的問題,需要大家多加小心。

寫這篇文章前一天,會因為沒有啟用 SMTP TLS 的關係而無法使用 Fast Server 的 SSL 模式,不過 aTech 已經在今天修好,目前使用上應該是不會碰到什麼太大的困難。