Google Cloudにメール受信用サーバを構築する!

2023-09-12

こんにちは。エヌデーデーの金子です。

皆さまメール送信するアプリを作る時、受信テストに困ったコトってないですか?

今回プロジェクトで大量(10,000件以上)メール送信機能を作るにあたり、
顧客の環境から実際にメールを飛ばしてパフォーマンスを見ることになりました。
その際メールの受け口どうしよう!となったたわけですが。。

・ Gmailやその他プロバイダのサービスを使うと、スパム判定が怖い!
・ example.comなどの例示用アドレスに送ると、受け取らないからリトライが嵩む!

等の理由から、テスト用のメール受信サーバ立てればよいのでは?という案が採択されました。
Google Cloud上に環境を作れば、手間暇かけずに出来ちゃうとの噂。早速やってみましょう。

※ 注意点 ※
Google Cloudの制限として、クラウド内からアウトバウンドへのSMTP通信はブロックされています!
外にメール送信したい時はSMTP リレーとしてSendGrid等サードパーティのサービスを使用する、等ひと工夫が要るみたいですね。

環境見取り図

Google Compute Engine(GCE)に立てたVMの中にメールサーバを構築し、外から通信できるようFWを設定します。

作業手順 

  1.  GCEにメールサーバとして動かすVMを作成し、外部IPを予約
  2.  Cloud Domainsでドメインを登録し、Cloud DNSでIPと紐づける
  3.  FWルールを設定する
  4.  VMにPostfix, Dovecotをインストールして設定
  5.  SSLサーバ証明書を取得して設定  ※暗号化通信をする場合
  6.  OSユーザを追加して動作確認

GCEにメールサーバとして動かすVMを作成し、外部IPを予約

まずはGCEにインスタンスを立てます。
外と通信できるように外部IPアドレスを予約し、FWルールのターゲットとするためにネットワークタグを設定します。サーバOSはdebianになるよう、ブートディスクのイメージを設定しています。

Cloud Domainsでドメインを登録し、Cloud DNSでIPと紐づける

Cloud Domainsでドメインを登録します。(一番安価で1400円/年)

※ドメイン名は何でもよい。。と思ったのですが、末尾で違いがあるようです。
値段の他に、「.dev」だとHTTPS通信が必要になるみたいなので、注意しましょう!

取得したドメイン名を使って、Cloud DNSの設定をします。
AレコードにVMインスタンスの外部IPアドレスを設定し、
MXレコードにAレコードのDNS名を設定します。

※ここでは仮にドメイン名を「domain.com」とします。
送信時Toアドレスに書くドメイン名は、【MXレコードのDNS名】である事に注意です!

上記の例だと、以下のように設定しています。

Aレコード:mail.domain.com 【VMインスタンスに割り振った外部IPアドレス】

MXレコード:domain.com 【優先度 + mail.domain.com 】

FWルールを設定する

ターゲットタグにVMインスタンスを指定し、FWルールを作成します。
外からのメールはSMTPポートで通信してくるので、通行を許可します。

25番 :SMTP通信
465番:暗号化SMTP通信

POPやIMAPは、サーバ外からメーラとかで受信メールを確認する場合は解放しましょう。
本題から外れますが、Internet-Aware Proxyを使用すると22番ポートをインターネットに公開することなくブラウザからSSH接続出来て便利です。

TCP 転送での IAP の使用

VMにPostfix, Dovecotをインストールして設定

ここからVM内のアプリケーションの設定です。
debian + Postfix(SMTP) + Dovecot(POP/IMAP)でサーバ内を構築していきます。

※ 設定を始める前に ※

「メールサーバ構築」で情報を漁ると、SMTP + POPの構成がよく出てきます。
今回参考にしたサイトもそのような構成でしたので、Postfix + Dovecotで作っています。
ですが作りたいのは平文で送信されたメールを受け取るサーバなので、Postfixのみ設定すればOKでした。
外部からのメールはPostfixで受け、内容もサーバ内ログで確認可能です!

メールクライアントツールで外部から受信メールの確認・管理をしたい場合は、Dovecotを入れます。
メールの暗号化通信を行うには、SSL証明書を入れましょう。

ここから先の設定は各ツールのバージョンに依ってしまうと思います。
またどの設定がクリティカルなのか筆者も自信がないので、あくまで参考程度を推奨です!

【バージョン情報】
debian 11.6
Postfix 3.5.17
Dovecot 2.3.13

【参考資料】
Debian 11 Mailサーバの構築
SSLメールサーバ構築メモ Let’s Encrypt+Postfix+Dovecot
Postfix 基本設定

Postfix(SMTPサーバ)

Postfixインストール

#インストール
apt -y install postfix sasl2-bin 

#confファイルコピー
cp /usr/share/postfix/main.cf.dist /etc/postfix/main.cf

#confを編集(※後述)
vi /etc/postfix/main.cf

#エイリアスを有効化
newaliases

#スタート
systemctl restart postfix

★Postfix設定・デフォルトからの変更点
「postconf -n」コマンドでデフォルトからの変更点を取得できます。

alias_database = hash:/etc/aliases
alias_maps = hash:/etc/aliases
command_directory = /usr/sbin
compatibility_level = 2
daemon_directory = /usr/lib/postfix/sbin
data_directory = /var/lib/postfix
debugger_command = PATH=/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin ddd $daemon_directory/$process_name $process_id & sleep 5
disable_vrfy_command = yes
home_mailbox = Maildir/
inet_interfaces = all
inet_protocols = ipv4
local_recipient_maps = unix:passwd.byname $alias_maps
mail_owner = postfix
mailq_path = /usr/bin/mailq
message_size_limit = 10240000
mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain
mydomain = domain.com
myhostname = mail.domain.com
mynetworks = 127.0.0.0/8,10.0.0.0/24
mynetworks_style = subnet
myorigin = $mydomain
newaliases_path = /usr/bin/newaliases
sendmail_path = /usr/sbin/postfix
setgid_group = postdrop
smtp_tls_mandatory_protocols = !SSLv2, !SSLv3
smtpd_banner = $myhostname ESMTP
smtpd_helo_required = yes
smtpd_recipient_restrictions = permit_mynetworks, permit_auth_destination, permit_sasl_authenticated, reject
smtpd_sasl_auth_enable = yes
smtpd_sasl_local_domain = $myhostname
smtpd_sasl_path = private/auth
smtpd_sasl_security_options = noanonymous
smtpd_sasl_type = dovecot

#↓↓↓↓↓↓↓↓↓ SSL証明書をインストールしてから設定する ↓↓↓↓↓↓↓↓↓
smtpd_tls_cert_file = /etc/letsencrypt/live/mail.domain.com/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/mail.domain.com/privkey.pem
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtpd_use_tls = yes
#↑↑↑↑↑↑↑↑↑ SSL証明書をインストールしてから設定する ↑↑↑↑↑↑↑↑↑

unknown_local_recipient_reject_code = 550

ここでのポイントは以下の設定です。

myhostname=【Aレコードのドメイン名】
mydomain = 【MXレコードのドメイン名】 

※mydomainのデフォルト値はmyhostnameから初めの要素を覗いた値がデフォルト値になるとのこと
 test.domain.comなら、domain.comとなるということですね。

Dovecot(POP/IAMPサーバ)

Dovecotインストール

#インストール
apt -y install dovecot-core dovecot-pop3d dovecot-imapd

#設定ファイルを編集(後述)
vi /etc/dovecot/dovecot.conf
vi /etc/dovecot/conf.d/10-auth.conf
vi /etc/dovecot/conf.d/10-mail.conf
vi /etc/dovecot/conf.d/10-master.conf

#スタート
systemctl restart dovecot

★Dovecot設定・デフォルトからの変更点
「doveconf -n コマンドでデフォルトからの変更点を取得できます。
※「# hidden, use -P to show it」のように情報が非表示になっているときは、案内通り「-P」コマンドを入力すると現れます。

また、この設定確認コマンドは一部きちんと表示されないことがあります。
(※下記の例だと、protocolsがダブルクォート括りになっている)
その場合「doveconf -d 【パラメータ名】」で個々の設定を確認できます。

auth_mechanisms = plain login
disable_plaintext_auth = no
log_path = /var/log/dovecot/dovecot.log
mail_location = maildir:~/Maildir
mail_privileged_group = mail
namespace inbox {
  inbox = yes
  location = 
  mailbox Drafts {
    special_use = \Drafts
  }
  mailbox Junk {
    special_use = \Junk
  }
  mailbox Sent {
    special_use = \Sent
  }
  mailbox "Sent Messages" {
    special_use = \Sent
  }
  mailbox Trash {
    special_use = \Trash
  }
  prefix = 
}
passdb {
  driver = pam
}
protocols = " imap pop3"
service auth {
  unix_listener /var/spool/postfix/private/auth {
    group = postfix
    mode = 0666
    user = postfix
  }
}
service imap-login {
  inet_listener imap {
    port = 0
  }
  inet_listener imaps {
    port = 993
    ssl = yes
  }
}
service pop3-login {
  inet_listener pop3 {
    port = 0
  }
  inet_listener pop3s {
    port = 995
    ssl = yes
  }
}

#↓↓↓↓↓↓↓↓↓ SSL証明書をインストールしてから設定する ↓↓↓↓↓↓↓↓↓
ssl_cert = </etc/letsencrypt/live/mail.domain.com/fullchain.pem
ssl_key = # hidden, use -P to show it
#↑↑↑↑↑↑↑↑↑ SSL証明書をインストールしてから設定する ↑↑↑↑↑↑↑↑↑

userdb {
  driver = passwd
}

SSLサーバ証明書を取得して設定

※暗号化しない25番の通信で充足であるならば、この設定はしなくても大丈夫です!※

暗号化通信を行う場合は取得します。
SSL証明書はLet’s Encrypt証明書なる無料のサービスを使います。
SSL 証明書を取得する (Let’s Encrypt)

Google CloudでもSSL証明書のサービスがあるようですが、ロードバランサを導入する必要があるとのことで、採用を見送りました。
Google マネージド SSL 証明書を使用する

Let’s Encrypt証明書を使用するにあたって、以下注意してください!

Aレコードのドメイン名=myhostnameに設定したドメインに対して取得すること
インストールの際は、TCP80番ポートを空けておくこと
証明書の有効期限は90日であること

#証明書取得ツールをインストール
apt -y install certbot

#standalone指定で簡易Webサーバ機能を使いながら証明書を取得
certbot certonly --standalone -d 【Aレコードのドメイン名】

#成功した場合
IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/mail.domain.com/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/mail.domain.com/privkey.pem
   Your certificate will expire on 2021-11-17. To obtain a new or
   tweaked version of this certificate in the future, simply run
   certbot again. To non-interactively renew *all* of your
   certificates, run "certbot renew"
 - If you like Certbot, please consider supporting our work by:

fullchain.pem ⇒ 中間証明書を含んだサーバ証明書
privkey.pem  ⇒ 秘密鍵
です。これを取得したら、PostfixとDovecotに設定します。
SSL/TLSの設定

/etc/postfix/main.cf

#最終行に追記
smtpd_tls_cert_file = /etc/letsencrypt/live/mail.domain.com/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/mail.domain.com/privkey.pem
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtpd_use_tls = yes

/etc/dovecot/conf.d/10-ssl.conf

# 6行目 : 変更
ssl = yes

# 12,13行目 : コメント解除して証明書/鍵ファイル指定
ssl_cert = </etc/letsencrypt/live/mail.domain.com/fullchain.pem
ssl_key = </etc/letsencrypt/live/mail.domain.com/privkey.pem

OSユーザを追加して動作確認

お疲れさまでした。

ここまでの設定が終わったら、メールの受信が出来る筈です。ユーザを追加して動作確認を行います!

# メールクライアントインストール
root@mail:~# apt -y install mailutils

# メールボックスは Maildir を参照するよう設定
root@mail:~# echo 'export MAIL=$HOME/Maildir/' >> /etc/profile.d/mail.sh

# OS ユーザー [debian] を追加
root@mail:~# adduser debian

メーラからは【OSユーザ名】@【MXレコードのDNS名】で送ります。

送信したらメールサーバでメールボックスを確認します。

#宛先のユーザとしてログイン
su - debian

#メールを確認する(※送ったメールが入っている筈!)
mail
"/home/debian/Maildir/": 24 messages 24 unread
>U   1 root               Tue Apr 18 10:50  13/581   test
 .
 .
 .
 U  24 NDD金子 悠里   Thu Apr 20 12:44 180/10738 OutLookから
?

この設定だとメールは「/home/【ユーザ名】/Maildir/」に貯まっていきます。
システムログは「/var/log/syslog」に出力されます。

※Dovecot2.3の受信エラー回避※

暗号化通信で受信エラーになった場合、 ssl_dhの設定をするとうまくいくかもしれません。

終わりに

いかがだったでしょうか。
筆者は普段の業務でまともにインフラ周りを意識していなかったので、アタマを抱えながら構築しました。
最後に、個人的な沼脱出のポイントを綴ります。

1.DNSにAレコードとMXレコードを登録すること
当初は「ドメインとIPの名前解決さえできればよい筈!」という考えの下、Aレコードのみ設定していましたが、メールサーバ構築にはMXレコードが必須の様です。 基本中の基本なんでしょうか。。笑

2.FWルールで上りSMTPポートを解放すること
受信できればよかったので、当初はPOPとIMAPだけ許可していました。また、 Google Cloudはメール送信できない、ということでSMTPポートの設定はそもそも要らないのかな、と思っていました。が、ブロックされるのは下りのSMTP通信とのことです。上りは許可しなければメールが届きませんでした。送信されたメールはあくまでSMTPで通信してきて、受信したメールを取り出すのにPOPやIMAPを使う。。というこれも基本中の基本なんでしょうね笑

3.postconf -n と doveconf -n を駆使して自分の設定値と上手くいってるケースの設定値を見比べること
PostfixとDovecotの設定は複数のconfファイルに手を入れるので、ミスしていても気づきにくいです。コマンドでデフォルト値との変更点を出して、網羅的に確認するのがおススメです。

上手くいかないときは
・ Google Cloudの設定が悪い
・ メールサーバとしての設定が悪い
のどちらかなので、切り分けて考えるようにするのがコツだなと感じます!
(そのアタリをつけるのが、すっごく難しいんですよね、きっと)

同じようにGoogle Cloud上でメールサーバ立てるのに苦心している方に届けば嬉しいです!!