ウェブサービスの開発では登録されたユーザーの確認などのために返信不可の送信専用メールを送る必要が出てくる. この機能の実装ができるよう、今回は Docker コンテナ内で動いている Debian 11 (bullseye) から Postfix を用いて送信専用メールを送れるように環境構築を行う.

例えば PHP からメールを送信する場合には mail 関数や mb_send_mail 関数といった関数が利用できるが、 これらの関数は pnp.ini に記述された sendmail_path の値を参照することでメール送信用のプログラム (MTA) を指定できるようになっている. (https://www.javadrive.jp/php/mailini/index1.html)

sendmail_path という名前なのだから sendmail というプログラムをインストールして使わなければならない. だから Postfix は関係ない」 …​というわけではなく、 sendmail の代わりに Postfix をインストールしても全く問題なくメール送信できるので sendmail を使わなければならないと思っていた人も一旦 Postfix を試してみて欲しい.

前提 1: メール送受信システムの構成要素

メーラーの設定に慣れている人ならば、メールの送信と受信にはそれぞれ異なるプロトコルが使われていることを知っているだろう. メール送信の際には SMTP (Simple Mail Transfer Protocol) というプロトコル、受信の際には POP3 (Post Office Protocol 3)IMAP (Internet Message Access Protocol) というプロトコルが使われている.

しかし、Postfix を使った送信専用メールのような「メーラーを使わないメール送受信のための設定」を行う場合、 MTA とか MDA のような今まで見たことのない略称がたくさん出てきて混乱すると思われる.

よって最初に前提として、メールの送受信を行っているシステム全体の構造について理解しておくのが良いだろう.

                          SMTP         +----------------------------------+
                         +-------------|--------------------+        SMTP |
                         |             |                    |             |
                         v             |                    |             v
+-------------+       +-----+   +------------+        +------------+   +-----+   +-------------+
| MDA (Local) |<------| MTA |-->| MDA (SMTP) |        | MDA (SMTP) |<--| MTA |-->| MDA (Local) |
+-------------+       +-----+   +------------+        +------------+   +-----+   +-------------+
   |                     ^                                                ^                 |
   v                     |                                                |                 v
+---------+           +-----+                                          +-----+       +---------+
|         |           | MSA |                                          | MSA |       |         |
| mailbox |           +-----+                                          +-----+       | mailbox |
|         |              ^                                                ^          |         |
+---------+              |   SMTP                                    SMTP |          +---------+
   |                SMTP |<------+                                        |                 |
   |                     |       |                                   +----|----+  IMAP/     v
   v                +----|----+  |                                   | +-----+ |   POP3  +-----+
+-----+  IMAP/POP3  | +-----+ |  |                                   | | MUA |<----------| MAA |
| MAA |------+------->| MUA | |  |                                   | +-----+ |         +-----+
+-----+      |      | +-----+ |  |                                   +---------+
             |      +---------+  |
             |                   |
             |      +---------+  |
             |      | +-----+ |  |
             +------->| MRA | |  |
                    | +-----+ |  |
                    |    |    |  |
                    |    v    |  |
                    | +-----+ |  |
                    | | MUA |----+
                    | +-----+ |
                    +---------+

SMTP、 POP3、 IMAP といったプロトコルは、この図中のメールシステムの各コンポーネント間の通信で使われている. メールシステムの各コンポーネントの役割はそれぞれ以下の通りである.

  • MUA (Mail User Agent)

    • 所謂メーラー. メールの読み書きを行い、SMTP を使った MTA へのメール送信や MRA を用いたメール受信を行う.

    • 具体例: Outlook Express や Mozilla Thunderbird など.

  • MSA (Mail Submission Agent)

    • MUA から送られてきたメールを受け取り、MTA に受け渡す.

    • 具体例: Postfix postdrop + pickup や sendmail-msa など.

  • MTA (Mail Transfer Agent)

    • 渡されたメールのルーティング (どこに送信すべきかの仕分け) を行い、どの MDA がメールを配信すべきかを決定する.

    • 郵便局で働いている仕分け担当の局員に例えられる.

    • 具体例: Postfix cleanup + qmgr + trivial-rewrite や Sendmail など.

  • MDA (Mail Delivery Agent)

    • MTA から渡されたメールをローカルのメールボックスや他の MTA 宛に送信する.

    • 郵便局から郵便物の配送に向かう配達員に例えられる.

    • 具体例: Postfix local, smtp, pipe や mail.local (ローカル配信用) など.

  • MAA (Mail Access Agent)

    • MUA (あるいはユーザー) の認証を行い、メールボックス中のメールの読み出しを行うことで MUA からメールを閲覧可能にする.

    • 具体例: Courier IMAPD

  • MRA (Mail Retrieval Agent)

    • MAA からメールを受け取り、MUA からメールを閲覧可能にする.

    • 具体例: Fetchmail あるいは Thunderbird などのメーラーに統合されている.

このようにメールの送受信のためのシステムは多数の構成要素に分かれている.

なお、メーラーの設定時に SMTP サーバPOP3 サーバ のアドレスやポート番号の入力を求められる場合があるが、 MTA や MDA は SMTP サーバ内にインストール されており、 MAA は POP3 サーバにインストール されていると思っておくと良いだろう.

次に、ここでインストールする Postfix というソフトウェアの役割について理解しておこう.

前提 2: Postfix とは

Postfix はオープンソースのメール転送エージェント (MTA) である.

すなわち、Postfix は MTA として宛先ごとにメールの仕分けをしたり送信するメールを MDA に依頼する役割のソフトウェアであり、SMTP サーバ内で動作するソフトウェアである.

なお Postfix 自体は MTA として紹介されるが、 実際には Postfix は MSA としての機能も持っているほかに mail.local という MDA も従えているため、メール送信のための大半の機能を Postfix だけで賄うことができる といえる.

MTA ソフトウェアとしては sendmail が最も古参 (初回リリースは 40 年前) かつ有名だが、設定ファイルが複雑かつ動作が遅いという古くからあるソフトウェア故の使いにくさがある. Postfix は sendmail 互換で現在最も活発に開発が行われている MTA である. sendmail、Postfix 以外の MTA としては qmailExim なども利用されている.

今回は送信専用のメールを送ることができれば十分なので、 MTA / MSA / MDA として機能する Postfix しか利用しないが、 もしも受信も可能なメールサーバを用意したいとなれば MAA として機能するソフトウェアも必要となる. Unix 系のシステムでは POP3 および IMAP サーバとして利用できる Dovecot が利用される場合が多いようだ.

前提 3: MTA と DNS の関係

会社などの特定の組織が社内メール用にメールサーバを構築した場合、MTA である Postfix は SMTP サーバ内にインストールされて動作する. SMTP サーバにはその会社の全従業員からのメールが届くことになるため、Postfix はそれぞれのメールの宛先を確認して各メールをどこに送信するべきかを仕分けすることとなる.

なお、この時 必ずしもすべてのメールが外部のサーバに送信されるわけではない という点に注意. メールの仕組みは現実の郵便の仕組みとよく似ているため、郵便の例で確認してみよう.

ある地域でポストに投函された郵便物はすべて最寄りの郵便局に集められ、その中で局員 (MTA) によって宛先ごとに仕分けが行われる. このとき、もしもある郵便が 同じ地域に住んでいる人宛だったならば、その郵便は他の郵便局に送られることなくそのまま配達員 (MDA) によって配達される のが普通ではないだろうか. メールの場合も同様であり、 MTA は 宛先がそのメールサーバの組織と同じになっているメール は外部に送信せずに、 mail.local などのローカル用の MDA を用いてそのままローカルのメールボックスに保存する.

例えば "株式会社ほげほげ" という会社が社内にメールサーバを構築し、各社員が [email protected] のようなメールアドレスでメールの送受信ができるようになっているとする. このとき、スタッフ A さん ([email protected]) からスタッフ B さん ([email protected]) 宛にメールを送ったとすると、そのメールは社内の SMTP サーバで MTA によって仕分けされた結果、外部の SMTP サーバに送られることなく社内のメールボックスに保存され、社内の POP3 サーバや IMAP サーバの MAA から取得されてスタッフ B さんの MUA に送信されることとなる.

MTA によって仕分けされ、外部に送信する必要があると判断されたメールはそれぞれ対応する外部の SMTP サーバに送信されることとなる. では、 どうやって MTA は宛先のメールアドレスから送信先の SMTP サーバを判断しているのだろうか?

ここで登場するのが DNS サーバに登録されている MX レコード である. ドメイン名と IP アドレスの対応関係を記述する DNS サーバには A レコードや CNAME レコード以外に MX レコード というレコードを記述することができ、 この中には "対象ドメイン宛のメールの配送先 (メールサーバ) のホスト名" を記述することができる.

例えばメールの宛先が [email protected] だったとする. @ の右側のドメイン名 gmail.comdig コマンドを用いて DNS に問い合わせてみると以下のような結果となった.

$ dig gmail.com MX

; <<>> DiG 9.10.6 <<>> gmail.com MX
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 53481
;; flags: qr rd ra; QUERY: 1, ANSWER: 5, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;gmail.com.                     IN      MX

;; ANSWER SECTION:
gmail.com.              3600    IN      MX      20 alt2.gmail-smtp-in.l.google.com.
gmail.com.              3600    IN      MX      30 alt3.gmail-smtp-in.l.google.com.
gmail.com.              3600    IN      MX      10 alt1.gmail-smtp-in.l.google.com.
gmail.com.              3600    IN      MX      5 gmail-smtp-in.l.google.com.
gmail.com.              3600    IN      MX      40 alt4.gmail-smtp-in.l.google.com.

;; Query time: 97 msec
;; SERVER: 218.219.82.240#53(218.219.82.240)
;; WHEN: Wed Jan 11 04:04:10 JST 2023
;; MSG SIZE  rcvd: 161

すると、 gmail-smtp-in.l.google.comalt1.gmail-smtp-in.l.google.comalt2.gmail-smtp-in.l.google.comalt3.gmail-smtp-in.l.google.comalt4.gmail-smtp-in.l.google.com という 5 つの MX レコードが登録されていることがわかった. このとき、ドメイン名の前に付与されている 520 といった整数はそのドメイン名の 優先度 であり、数字が小さいほど優先度が高いと解釈される. したがって、この場合は gmail-smtp-in.l.google.com というドメイン名が最も優先度が高いわけである.

次に、この gmail-smtp-in.l.google.com というドメインについても dig コマンドで調べてみよう.

$ dig gmail-smtp-in.l.google.com

; <<>> DiG 9.10.6 <<>> gmail-smtp-in.l.google.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 44019
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 4, ADDITIONAL: 9

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;gmail-smtp-in.l.google.com.    IN      A

;; ANSWER SECTION:
gmail-smtp-in.l.google.com. 300 IN      A       142.251.8.26

;; AUTHORITY SECTION:
google.com.             171209  IN      NS      ns2.google.com.
google.com.             171209  IN      NS      ns1.google.com.
google.com.             171209  IN      NS      ns3.google.com.
google.com.             171209  IN      NS      ns4.google.com.

;; ADDITIONAL SECTION:
ns4.google.com.         21315   IN      A       216.239.38.10
ns4.google.com.         21315   IN      AAAA    2001:4860:4802:38::a
ns2.google.com.         21315   IN      A       216.239.34.10
ns2.google.com.         21315   IN      AAAA    2001:4860:4802:34::a
ns1.google.com.         21315   IN      A       216.239.32.10
ns1.google.com.         21315   IN      AAAA    2001:4860:4802:32::a
ns3.google.com.         96734   IN      A       216.239.36.10
ns3.google.com.         96931   IN      AAAA    2001:4860:4802:36::a

;; Query time: 12 msec
;; SERVER: 192.168.137.1#53(192.168.137.1)
;; WHEN: Wed Jan 11 12:07:14 JST 2023
;; MSG SIZE  rcvd: 319

これにより、 gmail-smtp-in.l.google.com というドメインに対応している IP アドレスは 142.251.8.26 であるとわかったため、 MTA はこの IP アドレス宛に [email protected] 宛のメールを送信することとなる.

これが MTA の外部 SMTP サーバにメールを送信するときの動作原理となっている.

Debian 11 への Postfix のインストール・設定

では Docker コンテナ内で Debian 11 を動かし、その中から Postfix を使ってメールの送信を行ってみよう.

最初に Debian 11 の Docker イメージを取得する.

$ docker pull debian:bullseye

Docker コンテナを起動しよう. 今回は bash をバックグラウンドで起動することでコンテナが終了しないようにしておくこととする. なお SMTP の通信では 25 番ポートを使うが、今回はローカル以外の他のホストからのメールを受け付けないためポートフォワーディングの設定は一切入れないでおく. (下手にポートを開けておいてしまうと、迷惑メール送信の際の踏み台に利用されるケースなどもあるため危険.)

$ docker run -itd debian:bullseye /bin/bash
9c33e656a29083811f7465284f563682622d2bb19266ceb898b93950ddd0f722

起動しているかを確認しておく.

$ docker ps
CONTAINER ID  IMAGE            COMMAND      CREATED         STATUS         PORTS  NAMES
9c33e656a290  debian:bullseye  "/bin/bash"  21 seconds ago  Up 20 seconds         awesome_boyd

では、 bash を起動してコンテナ内に入ってみよう.

$ docker exec -it 9c33 /bin/bash
root@9c33e656a290:/#

まずは apt update を行ってパッケージの情報を最新に更新し、続けて apt installvimtelnet および tree をインストールしておこう.

root@9c33e656a290:/# apt update
Get:1 http://deb.debian.org/debian bullseye InRelease [116 kB]
Get:2 http://deb.debian.org/debian-security bullseye-security InRelease [48.4 kB]
Get:3 http://deb.debian.org/debian bullseye-updates InRelease [44.1 kB]
Get:4 http://deb.debian.org/debian bullseye/main arm64 Packages [8072 kB]
Get:5 http://deb.debian.org/debian-security bullseye-security/main arm64 Packages [207 kB]
Get:6 http://deb.debian.org/debian bullseye-updates/main arm64 Packages [12.0 kB]
Fetched 8499 kB in 5s (1800 kB/s)
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
All packages are up to date.

root@9c33e656a290:/# apt install -y vim telnet tree
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
  libgpm2 netbase vim-common vim-runtime xxd
Suggested packages:
  gpm ctags vim-doc vim-scripts
The following NEW packages will be installed:
  libgpm2 netbase telnet vim vim-common vim-runtime xxd
0 upgraded, 7 newly installed, 0 to remove and 0 not upgraded.
Need to get 8156 kB of archives.
After this operation, 37.2 MB of additional disk space will be used.
Get:1 http://deb.debian.org/debian bullseye/main arm64 netbase all 6.3 [19.9 kB]
Get:2 http://deb.debian.org/debian bullseye/main arm64 xxd arm64 2:8.2.2434-3+deb11u1 [192 kB]
Get:3 http://deb.debian.org/debian bullseye/main arm64 vim-common all 2:8.2.2434-3+deb11u1 [226 kB]
Get:4 http://deb.debian.org/debian bullseye/main arm64 telnet arm64 0.17-42 [69.0 kB]
Get:5 http://deb.debian.org/debian bullseye/main arm64 libgpm2 arm64 1.20.7-8 [35.9 kB]
Get:6 http://deb.debian.org/debian bullseye/main arm64 vim-runtime all 2:8.2.2434-3+deb11u1 [6226 kB]
Get:7 http://deb.debian.org/debian bullseye/main arm64 vim arm64 2:8.2.2434-3+deb11u1 [1388 kB]
Fetched 8156 kB in 3s (2354 kB/s)
...
Processing triggers for libc-bin (2.31-13+deb11u5) ...
root@9c33e656a290:/#

では、Postfix をインストールしてみよう. なお、Postfix のインストールは途中で設定ファイルを生成するための対話型プロンプトが表示されるため、ここでは DEBIAN_FRONTEND=noninteractive を付与することで対話型プロンプトの表示をスキップしてとりあえずデフォルトの設定ファイルを生成するように指定している. (https://zenn.dev/flyingbarbarian/articles/5bb1d38b1ada40)

root@9c33e656a290:/# DEBIAN_FRONTEND=noninteractive apt install -y postfix
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
  ca-certificates cpio libexpat1 libicu67 libmpdec3 libncursesw6 libpython3-stdlib
  libpython3.9-minimal libpython3.9-stdlib libreadline8 libsasl2-2 libsasl2-modules
  libsasl2-modules-db libsqlite3-0 media-types openssl python3 python3-minimal python3.9
  python3.9-minimal readline-common ssl-cert
Suggested packages:
  libarchive1 libsasl2-modules-gssapi-mit | libsasl2-modules-gssapi-heimdal libsasl2-modules-ldap
  libsasl2-modules-otp libsasl2-modules-sql procmail postfix-mysql postfix-pgsql postfix-ldap
  postfix-pcre postfix-lmdb postfix-sqlite sasl2-bin | dovecot-common resolvconf postfix-cdb
  mail-reader ufw postfix-doc python3-doc python3-tk python3-venv python3.9-venv python3.9-doc
  binutils binfmt-support readline-doc
The following NEW packages will be installed:
  ca-certificates cpio libexpat1 libicu67 libmpdec3 libncursesw6 libpython3-stdlib
  libpython3.9-minimal libpython3.9-stdlib libreadline8 libsasl2-2 libsasl2-modules
  libsasl2-modules-db libsqlite3-0 media-types openssl postfix python3 python3-minimal python3.9
  python3.9-minimal readline-common ssl-cert
0 upgraded, 23 newly installed, 0 to remove and 0 not upgraded.
Need to get 17.7 MB of archives.
After this operation, 64.1 MB of additional disk space will be used.
Get:1 http://deb.debian.org/debian bullseye/main arm64 libpython3.9-minimal arm64 3.9.2-1 [797 kB]
Get:2 http://deb.debian.org/debian bullseye/main arm64 libexpat1 arm64 2.2.10-2+deb11u5 [84.1 kB]
...
Running hooks in /etc/ca-certificates/update.d...
done.
root@9c33e656a290:/#

インストールが完了したので続けて Postfix の設定を行っていく. 設定については https://www.rem-system.com/mail-postfix01/ の内容を参考にしていく.

Postfix の設定ファイルは /etc/postfix フォルダ内にまとめられているので、まずはこのフォルダの中身を見てみよう.

root@9c33e656a290:/# tree /etc/postfix/
/etc/postfix/
|-- dynamicmaps.cf
|-- dynamicmaps.cf.d
|-- main.cf
|-- main.cf.proto
|-- makedefs.out -> /usr/share/postfix/makedefs.out
|-- master.cf
|-- master.cf.proto
|-- post-install
|-- postfix-files
|-- postfix-files.d
|-- postfix-script
`-- sasl

この中で重要なファイルは main.cfmaster.cf の 2 つである. 今回は main.cf だけを編集することとなる.

まずは main.cf を誤って壊してしまってもすぐに復旧できるよう、 main.cf のバックアップファイルを作っておこう.

root@9c33e656a290:/# cp /etc/postfix/main.cf /etc/postfix/main.cf.org

では、この main.cf の中身を見てみよう.

main.cf
# See /usr/share/postfix/main.cf.dist for a commented, more complete version


# Debian specific:  Specifying a file name will cause the first
# line of that file to be used as the name.  The Debian default
# is /etc/mailname.
#myorigin = /etc/mailname

smtpd_banner = $myhostname ESMTP $mail_name (Debian/GNU)
biff = no

# appending .domain is the MUA's job.
append_dot_mydomain = no

# Uncomment the next line to generate "delayed mail" warnings
#delay_warning_time = 4h

readme_directory = no

# See http://www.postfix.org/COMPATIBILITY_README.html -- default to 2 on
# fresh installs.
compatibility_level = 2



# TLS parameters
smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
smtpd_tls_security_level=may

smtp_tls_CApath=/etc/ssl/certs
smtp_tls_security_level=may
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache


smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
myhostname = 9c33e656a290
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
mydestination = $myhostname, 9c33e656a290, localhost.localdomain, , localhost
relayhost =
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = all
inet_protocols = all

ここでは https://www.rem-system.com/mail-postfix01/ に従い、以下の 5 つのパラメータと maillog_file パラメータの合計 6 つのパラメータを設定してみよう.

  • myhostname

    • メールサーバ (SMTP サーバ) のホスト名を FQDN (fully qualified domain name, 完全修飾名) で指定する.

    • 例えば、 annpin.com というドメイン内で動いているメールサーバのホスト名が mail である場合、そのメールサーバの FQDN は mail.annpin.com となる.

    • デフォルトではシェル上で hostname コマンドを実行した際に表示されるローカルホスト名が設定されている. Docker コンテナ環境の場合、 9c33e656a290 のようなコンテナ ID が設定される.

    • なお、ウェブサーバ用のホストに Postfix もインストールした場合、デフォルトではこのパラメータの値は www.annpin.com のようなウェブサーバ用のホスト名が FQDN で設定されるがわかりにくいため、適宜 mail.annpin.com などのメールサーバ用のホスト名を設定するとよいだろう.

  • mydomain

    • メールのドメインを指定する. デフォルトでは myhostname に指定したホスト名のドメイン名部分がそのまま使用される. 例えば myhostnamemail.annpin.com とした場合、 mydomain の値はそのまま annpin.com に設定される.

    • したがって myhostname が適切に設定されていれば mydomain を設定する必要はないが、ここでは明示的に mydomain を設定しておくこととする.

    • もちろん、ドメイン名が myhostname に設定したものと異なる場合には必須の設定項目となる.

  • inet_interfaces

    • メールを受け取るネットワークインタフェースアドレスを設定する.

    • デフォルトでは all に設定されており、この状態では Postfix はどのコンピュータから SMTP で送られてきたメールも受け付けてくれるようになっている.

    • 今回は返信不可の送信専用メールをホスト自身から送るだけであり、他のコンピュータからのメールを仕分けする必要はないため localhost と設定することで他のコンピュータから送られてくるメールは受け取らないようにしておく.

    • もちろん、通常のメールサーバとして Postfix を使いたい場合にはこの値を all に設定しておけばよい.

    • なお、 mynetworks という項目は inet_interfaces と少し似ているが、この項目は "信頼したネットワーク" を記述しておくことで、指定された SMTP サーバからのリレー (後述) を許可する設定である. この項目を不用意に設定してしまうと 迷惑メールの中継サーバに使われてしまう可能性がある ため、基本的には触らないでおくとよいだろう.

  • inet_protocols

    • Postfix がメールの送信や受信に使用するプロトコル (IPv4 あるいは IPv6) を指定する.

    • デフォルトでは all となっているため、IPv4 と IPv6 の両方で待ち受けを行う.

    • IPv4 のみを利用する場合は ipv4 、 IPv6 のみを利用する場合には ipv6 と指定すれば良い.

    • 今回は ipv4 を指定しておく.

  • masquerade_domains

    • メールを外部に送信する際に、送信元のホスト名を取り除くことで外部から内部のホスト名を隠蔽するための設定.

    • このパラメータを指定しない場合、送信元の情報が [email protected] のように表示されるが、通常はメールアドレスには mail のようなサブドメイン (ホスト名) は表示しないことが多い. このオプションの指定を行うことで、 [email protected] のように表示されるようにすることができる.

    • mydomain で指定したものと同じドメイン名を指定すると良いだろう.

  • maillog_file

    • Postfix のログファイルの生成先パスを指定する.

    • Docker 中の Debian 11 でインストールした Postfix はデフォルトではログファイルを生成してくれないようなので、明示的に指定してやる必要がある.

    • ここでは /var/log/mail.log にログを出力するように設定する.

これらの設定を main.cf に書き込んだ結果は以下のようになる. なお、ここでは TLS による暗号化は行わないので TLS 関連のオプションはすべてコメントに変更しておいた.

main.cf
# See /usr/share/postfix/main.cf.dist for a commented, more complete version


# Debian specific:  Specifying a file name will cause the first
# line of that file to be used as the name.  The Debian default
# is /etc/mailname.
#myorigin = /etc/mailname

smtpd_banner = $myhostname ESMTP $mail_name (Debian/GNU)
biff = no

# appending .domain is the MUA's job.
append_dot_mydomain = no

# Uncomment the next line to generate "delayed mail" warnings
#delay_warning_time = 4h

readme_directory = no

# See http://www.postfix.org/COMPATIBILITY_README.html -- default to 2 on
# fresh installs.
compatibility_level = 2



# TLS parameters
# smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
# smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
# smtpd_tls_security_level=may
#
# smtp_tls_CApath=/etc/ssl/certs
# smtp_tls_security_level=may
# smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache


smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
myhostname = mail.annpin.com
mydomain = annpin.com
inet_interfaces = localhost
inet_protocols = ipv4
masquerade_domains = annpin.com
maillog_file = /var/log/mail.log
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
mydestination = $myhostname, 9c33e656a290, localhost.localdomain, , localhost
relayhost =
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
mailbox_size_limit = 0
recipient_delimiter = +

postconf -n というコマンドを実行すると、現在 Postfix に設定されている設定情報を表示することができる. 一度このコマンドを実行し、 main.cf に書き込んだ内容がきちんと認識されているかを確認しておくとよいだろう.

root@9c33e656a290:/# postconf -n
alias_database = hash:/etc/aliases
alias_maps = hash:/etc/aliases
append_dot_mydomain = no
biff = no
compatibility_level = 2
inet_interfaces = localhost
inet_protocols = ipv4
mailbox_size_limit = 0
maillog_file = /var/log/mail.log
masquerade_domains = annpin.com
mydestination = $myhostname, 9c33e656a290, localhost.localdomain, , localhost
mydomain = annpin.com
myhostname = mail.annpin.com
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
readme_directory = no
recipient_delimiter = +
relayhost =
smtpd_banner = $myhostname ESMTP $mail_name (Debian/GNU)
smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination

また、 postfix check コマンドを使うことで設定ファイルに誤りがないかを確認することができる. 以下のように実行してメッセージが何も表示されなければ Postfix の各設定ファイルは正しく記述されていることとなる.

root@9c33e656a290:/# postfix check
root@9c33e656a290:/#

一方、例えば main.cf において inet_protocols の値を all にしてから postfix check を実行すると、Docker 中の Debian 11 環境では以下のようなエラーメッセージが表示されることがわかる.

root@9c33e656a290:/# postfix check
postfix: fatal: parameter inet_interfaces: no local interface found for ::1
root@9c33e656a290:/#

::1 とは IPv6 におけるループバックアドレスのことであり、 IPv4 における 127.0.0.1 に相当するアドレスのことである. これは様々な記事で報告されているが、どうやら IPv6 が無効なシステムにおいて /etc/hosts 中に IPv6 のアドレスである ::1 の設定が記載されていると発生するようだ. inet_protocols の値を ipv4 から all に変更したことで IPv6 のアドレスもチェックするようになったが、Docker コンテナ環境中では IPv6 が有効になっていないためにこのようなエラーが発生するようだ.

/etc/hosts の中身を確認してみると、2 行目に確かに ::1 に対する設定が記述されている.

root@9c33e656a290:/# cat /etc/hosts
127.0.0.1       localhost
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.5      9c33e656a290

このエラーを解消するには inet_protocols の値を ipv4 に戻すか、 /etc/hosts の 2 行目を # 記号を使ってコメント化すると良いだろう.

設定に問題がないことを確認したら、Postfix サービスを起動してみよう.

今どきの Linux サーバではサービスの起動には systemctl コマンドを使う場合が多いだろうが、今回の Docker 環境中の Debian 11 では service コマンドを用いる.

root@9c33e656a290:/# service --status-all
 [ ? ]  hwclock.sh
 [ - ]  postfix

root@9c33e656a290:/# service postfix start
Starting Postfix Mail Transport Agent: postfix.

root@9c33e656a290:/# service --status-all
 [ ? ]  hwclock.sh
 [ + ]  postfix

systemctl を使う場合には systemctl start postfix で Postfix を起動できるだろう. また、 systemctl enable postfix で Postfix を OS 起動時に自動起動させるように設定することもできるはずだ.

Docker を用いてウェブサービスの運用を行う場合にはコンテナが起動するたびに毎回新しい環境が生成されることとなるため、サービスの自動起動を登録してもあまり意味がないだろう. Docker 環境中で Postfix サービスを自動的に起動させるようにするためには、 CMD あるいは ENTRYPOINTservice start postfix の実行が含まれるシェルスクリプトが指定された Dockerfile を用意してやるしかなさそうだ. (https://stackoverflow.com/a/25150809/3342121)

Postfix からのメール送信

では、Postfix を用いてメールを送信してみよう.

まずは telnet コマンドを用い、Docker コンテナ内の 25 番ポートで動いている SMTP サーバである Postfix に対して直接メールを送信してみよう. いきなり外部の SMTP サーバに転送されるメールを作るのではなく、まずは同一ドメインの他のユーザに対するメールを書いてみる. これにより、ローカルのメールボックスにメールが送信されるはずだ.

Docker コンテナ内で操作を行っているので、現在のユーザは root となっている. また /etc/passwd の中身を確認することで現在のシステム上に存在しているユーザの一覧を確認することができる.

root@9c33e656a290:/# id
uid=0(root) gid=0(root) groups=0(root)

root@9c33e656a290:/# cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
postfix:x:101:102::/var/spool/postfix:/usr/sbin/nologin

今回は root ユーザから postfix ユーザに対してメールを送ってみよう. それぞれのユーザのメールアドレスは ユーザ名@ホスト名 という形となっている.

telnet コマンドを用いたメール送信は以下のように行えばよい. (telnet でのメール送信の詳細については http://www.mm-labo.com/computer/linux/mail-telnet-smtp.html を参照すること.)

root@9c33e656a290:/# telnet localhost 25
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 mail.annpin.com ESMTP Postfix (Debian/GNU)

helo localhost
250 mail.annpin.com

mail from:[email protected]
250 2.1.0 Ok

rcpt to:[email protected]
250 2.1.5 Ok

data
354 End data with <CR><LF>.<CR><LF>
test mail from root to postfix.
.
250 2.0.0 Ok: queued as E31534A30D7

quit
221 2.0.0 Bye
Connection closed by foreign host.
root@9c33e656a290:/#

これでメールが送信されたはずだが、念の為ログファイルも確認しておこう. Postfix のログ情報は /var/log/mail.log に書き出されているはずだ.

root@9c33e656a290:/# cat /var/log/mail.log
Jan 11 14:44:50 mail postfix/master[3654]: daemon started -- version 3.5.17, configuration /etc/postfix
Jan 11 15:06:50 mail postfix/smtpd[3686]: connect from localhost[127.0.0.1]
Jan 11 15:07:21 mail postfix/smtpd[3686]: E31534A30D7: client=localhost[127.0.0.1]
Jan 11 15:07:37 mail postfix/cleanup[3690]: E31534A30D7: message-id=<[email protected]>
Jan 11 15:07:37 mail postfix/qmgr[3661]: E31534A30D7: from=<[email protected]>, size=338, nrcpt=1 (queue active)
Jan 11 15:07:37 mail postfix/local[3691]: E31534A30D7: to=<[email protected]>, relay=local, delay=27, delays=27/0.02/0/0, dsn=2.0.0, status=sent (delivered to mailbox)
Jan 11 15:07:37 mail postfix/qmgr[3661]: E31534A30D7: removed
Jan 11 15:07:38 mail postfix/smtpd[3686]: disconnect from localhost[127.0.0.1] helo=1 mail=1 rcpt=1 data=1 quit=1 commands=5

すると、 mail postfix/local[3691]: E31534A30D7: to=<[email protected]>, relay=local, delay=27, delays=27/0.02/0/0, dsn=2.0.0, status=sent (delivered to mailbox) と書かれていることから問題なくメールの送信が完了していることがわかる.

メールボックスの実体は /var/mail の中であるようだ. 中身を確認してみよう.

root@9c33e656a290:/# cat /var/mail/postfix
From [email protected]  Wed Jan 11 15:07:37 2023
Return-Path: <[email protected]>
X-Original-To: [email protected]
Delivered-To: [email protected]
Received: from localhost (localhost [127.0.0.1])
        by mail.annpin.com (Postfix) with SMTP id E31534A30D7
        for <[email protected]>; Wed, 11 Jan 2023 15:07:10 +0000 (UTC)
Message-Id: <[email protected]>
Date: Wed, 11 Jan 2023 15:07:10 +0000 (UTC)
From: [email protected]

test mail from root to postfix.

root@9c33e656a290:/#

問題なくメールが受信できていることが確認できた.

毎回 telnet を用いたメール送信を行うのは少し面倒なので、今度は sendmail コマンドを使ってメールを送信してみよう. sendmail という名前のコマンドだが、メールは問題なく Postfix によって仕分けされることとなる.

root@9c33e656a290:/# sendmail [email protected]
From:[email protected]
To:[email protected]
Subject:Test mail 2

test mail from root to postfix again.

.
root@9c33e656a290:/#

再びメールボックスの中身を確認してみよう.

root@9c33e656a290:/# cat /var/mail/postfix
From [email protected]  Wed Jan 11 15:07:37 2023
Return-Path: <[email protected]>
X-Original-To: [email protected]
Delivered-To: [email protected]
Received: from localhost (localhost [127.0.0.1])
        by mail.annpin.com (Postfix) with SMTP id E31534A30D7
        for <[email protected]>; Wed, 11 Jan 2023 15:07:10 +0000 (UTC)
Message-Id: <[email protected]>
Date: Wed, 11 Jan 2023 15:07:10 +0000 (UTC)
From: [email protected]

test mail from root to postfix.

From [email protected]  Wed Jan 11 15:31:05 2023
Return-Path: <[email protected]>
X-Original-To: [email protected]
Delivered-To: [email protected]
Received: by mail.annpin.com (Postfix, from userid 0)
        id 7E62C4A30DA; Wed, 11 Jan 2023 15:31:05 +0000 (UTC)
From: [email protected]
To: [email protected]
Subject:Test mail 2
Message-Id: <[email protected]>
Date: Wed, 11 Jan 2023 15:30:14 +0000 (UTC)

test mail from root to postfix again.


root@9c33e656a290:/#

sendmail でも問題なくメール送信ができていることがわかる.


では、今度は外部のメールサーバに送信されるメールを送信してみよう. 例えば gmail 宛のメールを作ってみよう. sendmail コマンドを使うと以下のように書くことができる.

root@9c33e656a290:/# sendmail アカウント名@gmail.com
From:[email protected]
To:アカウント名@gmail.com
Subject:Test mail to gmail

test mail to gmail.

.

これで gmail 宛のメールを送信することができたはずだ. 自分のアカウントで gmail にログインし、メールが届いているかを確認してみよう.

…​いくら待っても gmail 宛のメールが届かない

おそらく、多くの環境では前節の最後に送信したメールはいくら待っても gmail で受信できないだろう. (無事にメールを受信できた人は、おめでとうございます.)

Postfix のログファイルを確認してみよう.

root@9c33e656a290:/# cat /var/log/mail.log
...
Jan 11 15:37:11 mail postfix/pickup[3660]: 391714A30DA: uid=0 from=<root>
Jan 11 15:37:11 mail postfix/cleanup[3705]: 391714A30DA: message-id=<[email protected]>
Jan 11 15:37:11 mail postfix/qmgr[3661]: 391714A30DA: from=<[email protected]>, size=313, nrcpt=1 (queue active)
Jan 11 15:37:11 mail postfix/smtp[3708]: connect to gmail-smtp-in.l.google.com[108.177.125.27]:25: Connection refused
Jan 11 15:37:12 mail postfix/smtp[3708]: connect to alt1.gmail-smtp-in.l.google.com[142.250.141.27]:25: Connection refused
Jan 11 15:37:12 mail postfix/smtp[3708]: connect to alt2.gmail-smtp-in.l.google.com[142.250.115.27]:25: Connection refused
Jan 11 15:37:13 mail postfix/smtp[3708]: connect to alt3.gmail-smtp-in.l.google.com[64.233.171.26]:25: Connection refused
Jan 11 15:37:14 mail postfix/smtp[3708]: connect to alt4.gmail-smtp-in.l.google.com[142.250.152.26]:25: Connection refused
Jan 11 15:37:14 mail postfix/smtp[3708]: 391714A30DA: to=<アカウント名@gmail.com>, relay=none, delay=39, delays=35/0.01/3.4/0, dsn=4.4.1, status=deferred (connect to alt4.gmail-smtp-in.l.google.com[142.250.152.26]:25: Connection refused)
root@9c33e656a290:/#

ログファイルの末尾の方を見てみると、 dig コマンドを使って gmail.com に対応している MX レコードを表示した際に表示された gmail-smtp-in.l.google.com などの 5 つのドメイン名が表示されていることがわかる. Postfix はこれらのドメインに対して優先度が高い順に順番に 25 番ポートで接続を試みているようだが、これらの接続がすべて Connection refused で失敗しているようだ.

この影響で gmail 宛のメールは送信に失敗しているということなのだろう.

同一ドメイン宛のメールはきちんと送信されていたのだから、Postfix 自体はきちんと動作していると考えられる.

何が問題なのだろうか?

(なお、上に示したログの内容とは全然異なるエラーが表示されている場合は こっち を参照すること.)

前提 4: 迷惑メール対策と OP25B (Outbound Port 25 Blocking)

この問題は、実は現在の多くのネットワークでは 外部のサーバに 25 番ポートで直接アクセスすることが禁止されている ということに由来する. 以前であれば先程設定した Postfix の設定で問題なく 25 番ポートを使って外部の SMTP サーバにメールを送信できていたわけだが、現在の多くの環境ではこれが禁止されているわけである.

root@9c33e656a290:/# telnet gmail-smtp-in.l.google.com 25
Trying 108.177.97.27...
Trying 2404:6800:4008:c00::1b...
telnet: Unable to connect to remote host: Cannot assign requested address
root@9c33e656a290:/#

ではなぜ 25 番ポートによる外部サーバへのアクセスが現在は禁止されているのかというと、 迷惑メール (spam) 対策 である.

Postfix の設定で見てきたように、SMTP によるメールの送信では基本的にそのメールの送り主についての 認証 は一切行わずにメールを自由に送信することができる. 認証も行わずに自由に外部の SMTP サーバに対してメールを一方的に送り付けることができるのだから、迷惑メールは誰でも簡単に大量に送信することができる状態になっていたわけである. したがって迷惑メール防止のために、各プロバイダ (ISP) は OP25B (Outbound Port 25 Blocking) と呼ばれる対策を行うことで、"自分のネットワーク外のコンピュータからの 25 番ポートでのアクセスを禁止" したわけである. (https://www.server-memo.net/server-setting/postfix/op25b_jitaku.html , https://www.infraexpert.com/study/tcpip18.html , https://www.coralnet.or.jp/support/entry-000131.html)

基本的に迷惑メールの送信者は "SMTP に認証が存在しない" ことを利用し、自分が契約しているプロバイダのメールサーバを使わずに外部の SMTP サーバに対して直接メール送信を行っていたため、 OP25B 対策によって大半の迷惑メールが抑制されることとなった. しかしこの副作用として、一般のメール利用者は 自宅ではプロバイダのメールサーバにアクセスしてメールを送信できるのに、ネットカフェなどの出先からはプロバイダのメールサーバにアクセスしてメールを送信することができなくなってしまった. これに対処するために、後述する 587 番ポートを用いた SMTP リレーと SMTP Auth によるメール送信方法が導入された.

OP25B 環境でのメール送信: SMTP リレー、SMTP Auth、Submission Port 587 / SMTP over SSL/TLS 465

OP25B の影響により、以下の模式図に示したように自宅に Postfix を用いた SMTP サーバを立ち上げても、gmail などの外部の SMTP サーバに対してはメールを送信することができなくなってしまったわけである.

   +-----+    +-------------------+    port 25 OK
   | ISP |----| ISP's mail server |<-------------.
   +-----+    +-------------------+              |
      |                                          v
+-----------+   +----------------+  OP25B  +---------------------+
| my router |---| my SMTP server | <-----> | gmail's SMTP server |
+-----------+   +----------------+         +---------------------+
      |
+-----------+
| my laptop |
+-----------+

図に示されているように、自宅でノート PC から自宅の SMTP サーバに 25 番ポートを使ってアクセスすることは OK だが、自宅の SMTP サーバから gmail の STMP サーバに 25 番ポートでアクセスすることは禁止されており、通信は遮断されることとなる. Postfix を用いて立てた自前のメールサーバを gmail などの外部の SMTP サーバと直接やり取りさせるためには、少なくとも OP25B を行っていないプロバイダのネットワーク下に存在させなければならない といえるだろう.

では、自宅にメールサーバを立てても全く意味がないのか? というと、そうではない.

OP25B 環境下でもメールを送信できるように考案された方法が SMTP Auth を用いて外部の SMTP サーバとの認証を行い、その外部 SMTP サーバに対して自分が送信したいメールの送信を委譲するという SMTP リレー を行うという方法である. 例えば自宅のプロバイダのメールサーバに対して SMTP リレーを設定すれば、自宅の SMTP サーバから自宅のコンピュータ宛ではないメールをすべてプロバイダのメールサーバに対して委譲し、そこから外部の SMTP サーバに送信してもらうように設定することができる.

この SMTP Auth と SMTP リレーを行う際には、25 番ポートの代わりに 587 番ポート (Submission port) あるいは 465 番ポート (SMTP over SSL/TLS) を用いる. なお、587 番ポートと 465 番ポートという 2 種類のポートがあるが、一般的には 587 番ポートが使われるのが普通であるようだ. (https://sendgrid.com/blog/whats-the-difference-between-ports-465-and-587/ , https://serverfault.com/questions/1026309/send-mail-via-port-465-or-587-on-google-cloud-vm-postfix)

例えば、一旦 587 番ポートでプロバイダのメールサーバにメールを送信できれば、プロバイダのメールサーバから外への通信は基本的に承認されたメールサーバ間のみの通信となるため、すべて 25 番ポートを用いた通信でメールを送受信することができる. (25 番以外のポートを用いた通信では SMTP Auth での認証も一緒にくっついてくるため、当然か.)

したがって、Postfix から自分のプロバイダのメールサーバに対して SMTP Auth と SMTP リレーでメールを委譲できれば外部のメールサーバにもメールを配信できそうである. しかし、環境によってはプロバイダがメールサーバを提供していない場合もあるかもしれない. 幸い、実は gmail の SMTP サーバは SMTP リレーの相手に設定することができる ようになっているので、この設定を行ってみよう.


なお、今回は関係ないが実は Postfix は master.cfsubmission セクションを有効にすることで、外部の SMTP サーバからの 587 番での SMTP リレー接続を受け入れることができるようになっている. その際、Postfix は MSA (Mail Submission Agent) として機能するといえる. (https://serverfault.com/questions/982121/does-postfix-also-operate-as-mail-submission-agent-msa)

SMTP Auth のためにアプリパスワードを取得し、smtp.gmail.com を SMTP リレー先に設定する

SMTP リレーを行うには SMTP Auth による認証が必要となる. SMTP Auth は基本的には単なるユーザー名とパスワードによる認証なのだが、ユーザー名として 自分の gmail のメールアドレス 、パスワードとしては アプリパスワード を使用する. まず gmail のアカウントを持っていない場合には Google のアカウントを作成しておく必要がある. また、アプリパスワードを生成するためには Google のアカウントの 2 段階認証設定が必要となるのでこれも同時に済ませておこう.

アプリパスワードを取得するには以下のようにすれば良い.

  1. 自分の Google アカウントで https://myaccount.google.com にアクセスし、 セキュリティ ページを開く.

  2. 2 段階認証プロセス がオンになっていない場合は、2 段階認証を有効化させておく.

  3. アプリ パスワード を開く.

  4. アプリを選択 から その他 (名前を入力) を選択し、 Postfix と入力してから 生成 をクリック. (名前は Postfix 以外でも何でも良い)

  5. 生成されたアプリ パスワード 画面上で 16 文字のアプリパスワードをコピーして保存しておく.

続けて、 Postfix から gmail の SMTP サーバに SMTP リレーおよび SMTP Auth するための設定を記述しよう.

最初に SMTP Auth で行われる SASL 認証のためのパッケージをインストールする.

root@9c33e656a290:/# apt install -y sasl2-bin

root@9c33e656a290:/# DEBIAN_FRONTEND=noninteractive apt install -y cyrus-imapd

/etc/postfix/gmail_passwd というファイルを作成し、この中に SMTP Auth のためのユーザー名とパスワードを記述しておこう.

gmail_passwd
[smtp.gmail.com]:587 アカウント名@gmail.com:アプリパスワード

続けて、このファイルのパーミッションを変更しておこう.

root@9c33e656a290:/# chmod 600 /etc/postfix/gmail_passwd

次に postmap というコマンドを使うことで /etc/postfix/gmail_passwd から /etc/postfix/gmail_passwd.db というファイルを生成しよう.

root@9c33e656a290:/# ls /etc/postfix
dynamicmaps.cf    main.cf        makedefs.out     post-install     postfix-script
dynamicmaps.cf.d  main.cf.org    master.cf        postfix-files    sasl
gmail_passwd      main.cf.proto  master.cf.proto  postfix-files.d

root@9c33e656a290:/# postmap /etc/postfix/gmail_passwd

root@9c33e656a290:/# ls /etc/postfix
dynamicmaps.cf    gmail_passwd.db  main.cf.proto  master.cf.proto  postfix-files.d
dynamicmaps.cf.d  main.cf          makedefs.out   post-install     postfix-script
gmail_passwd      main.cf.org      master.cf      postfix-files    sasl

/etc/postfix/main.cf の末尾に gmail の SMTP サーバを SMTP リレーの接続先として登録する設定を記述する. なお、デフォルトの main.cf では relayhost の設定が既に書いてあるので、デフォルトの relayhost の設定は削除あるいはコメント化しておこう.

main.cf
# See /usr/share/postfix/main.cf.dist for a commented, more complete version


# Debian specific:  Specifying a file name will cause the first
# line of that file to be used as the name.  The Debian default
# is /etc/mailname.
#myorigin = /etc/mailname

smtpd_banner = $myhostname ESMTP $mail_name (Debian/GNU)
biff = no

# appending .domain is the MUA's job.
append_dot_mydomain = no

# Uncomment the next line to generate "delayed mail" warnings
#delay_warning_time = 4h

readme_directory = no

# See http://www.postfix.org/COMPATIBILITY_README.html -- default to 2 on
# fresh installs.
compatibility_level = 2



# TLS parameters
# smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
# smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
# smtpd_tls_security_level=may
#
# smtp_tls_CApath=/etc/ssl/certs
# smtp_tls_security_level=may
# smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache


smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
myhostname = mail.annpin.com
mydomain = annpin.com
inet_interfaces = localhost
inet_protocols = ipv4
masquerade_domains = annpin.com
maillog_file = /var/log/mail.log
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
mydestination = $myhostname, 9c33e656a290, localhost.localdomain, , localhost
# relayhost =
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
mailbox_size_limit = 0
recipient_delimiter = +

# Gmail settings
relayhost = [smtp.gmail.com]:587
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/gmail_passwd
smtp_sasl_security_options = noanonymous
smtp_tls_security_level = encrypt

設定ファイルを更新したので、再度 postfix check を実行して設定ファイルを検証してから Postfix のサービスを再起動しよう.

root@9c33e656a290:/# postfix check

root@9c33e656a290:/# service postfix restart
Stopping Postfix Mail Transport Agent: postfix.
Starting Postfix Mail Transport Agent: postfix.

再度メールを送ってみよう.

root@9c33e656a290:/# sendmail アカウント名@gmail.com
From:[email protected]
To:アカウント名@gmail.com
Subject:Test mail to gmail

test mail to gmail.

.

ログファイルを確認してみると…​

root@9c33e656a290:/# cat /var/log/mail.log
...
Jan 12 13:14:51 mail postfix/master[4265]: daemon started -- version 3.5.17, configuration /etc/postfix
Jan 12 13:16:05 mail postfix/pickup[4271]: 677D54A30DA: uid=0 from=<root>
Jan 12 13:16:05 mail postfix/cleanup[4276]: 677D54A30DA: message-id=<[email protected]>
Jan 12 13:16:05 mail postfix/qmgr[4272]: 677D54A30DA: from=<[email protected]>, size=313, nrcpt=1 (queue active)
Jan 12 13:16:08 mail postfix/smtp[4278]: 677D54A30DA: to=<アカウント名@gmail.com>, relay=smtp.gmail.com[74.125.23.108]:587, delay=22, delays=19/0.03/1.6/1.1, dsn=2.0.0, status=sent (250 2.0.0 OK  1673529368 g131-20020a625289000000b005871b73e27dsm3064659pfb.33 - gsmtp)
Jan 12 13:16:08 mail postfix/qmgr[4272]: 677D54A30DA: removed
root@9c33e656a290:/#

問題なくメールが送れたようだ. gmail の受信ボックスを確認してみると、今度こそメールを受信できているはずだ.

なお、ウェブで Postfix の設定について調べてみると sasl2-bin パッケージをインストールすることで SASL 認証ができるように設定している例が多いが、これは Postfix に 587 番の Submission port で他のコンピュータからアクセスする際に使用する認証で必要になるものと思われる. 同様に、 cyrus-imapd パッケージは IMAP で Postfix から受信メールを取得する際に必要となるパッケージだろう.

↑ そんなことなかった. sasl2-bincyrus-imapdsmtp.gmail.com にアクセスした際の SASL 認証に必要なパッケージだった.

gmail に届いたメールの送信元が gmail アカウントに上書きされてしまう: gmail アカウントに他のメールアドレスを追加し、ドメインのメール転送設定から送信専用メールアドレスを作る

届いたメールを確認してみると、 sendmail を使った際に From に設定した送信元情報が自分の gmail のアドレスで上書きされてしまっていることがわかる. 実は、現在の gmail は From ヘッダーに設定したメールアドレスを勝手に書き換えてしまう仕様であるようだ. (https://serverfault.com/questions/249636/postfix-relays-via-gmail-from-email-is-wrong , https://serverfault.com/questions/152604/smtp-relay-through-gmail-overrides-from-address-with-megmail-com)

自分の gmail のメールアドレスがそのまま表示されてしまうとなると、そのメールに返信したらそのまま自分の gmail のメールアドレスに返信が届いてしまう. これでは送信専用メールとしては使えないだろう.

この問題を回避するためには、gmail の 設定 から アカウントとインポート を開き、 名前 (Gmail を使用して他のメール アドレスからメールを送信します) の箇所に 送信専用メールのメールアドレスを登録する という方法が使える. (https://www.value-domain.com/media/domain-usage-mail/)

戦略としては、 一旦送信専用メールのメールアドレスを DNS の Email forwarding 設定に登録し、gmail 上でそのメールアドレスを gmail アカウントに追加してから DNS の Email forwarding 設定を削除する というものである.

具体的な手順としては https://www.value-domain.com/media/domain-usage-mail/ を参照してほしいが、概略としては以下のようになる. なお、ここではドメインの管理に Google Domains を使っているものとする.

  1. Google Domains (https://domains.google.com/registrar/) にアクセスし、送信専用メールアドレスのドメイン名に対応するドメイン名を一覧から選択する.

  2. 左側のメニューから Email を選択し、 Email forwarding の中の Add email alias から送信専用メールアドレス (例えば [email protected]) が自分の gmail アドレスに転送されるように設定する.

  3. gmail の 設定 から アカウントとインポート を開き、 名前 (Gmail を使用して他のメール アドレスからメールを送信します) の箇所で 他のメールアドレスを追加 をクリックし、 Email forwarding で設定した送信専用メールアドレスを追加する.

  4. その後 SMTP サーバの設定画面に切り替わるので、 SMTP サーバーsmtp.gmail.comユーザー名 を自分の gmail のメールアドレスに設定し、 パスワード にアプリパスワードを入力して アカウントを追加 をクリックする.

  5. 確認コードの入力が求められるので、自分の gmail の受信ボックスに届いたメールを確認して確認コードを入力する.

  6. 追加完了後、再び Google Domains に戻って Email forwarding で送信専用メールアドレスの転送設定を削除する.

これで送信専用メールアドレスとして使うことができるようになった. これにより、例えば PHP からは以下のようにすることで送信専用メールを送ることができるようになった.

PHP のインストール
root@9c33e656a290:/# apt install -y php
mail.php
<?php

$to = 'ユーザーのメールアドレス';
$title = 'test title';
$body = 'test mail';
$headers = 'From: [email protected]' . "\r\n".'X-Mailer: PHP/'.phpversion();
echo(mail($to, $title, $body, $headers));
メールの送信
root@9c33e656a290:/# php mail.php

さらなる設定について

ここでは Docker 環境中から Postfix を用いて送信専用メールを送る方法を見てきたが、 より詳しい Linux でのサーバ構築については以下のシリーズを参照するのが良さそうだ.

Postfixが全然違うエラーを出す場合

OP25B が設定されていない 25 番ポートが解放されている環境の場合、上に示したエラーとは異なるエラーを Postfix が出力するかもしれない.

telnet で gmail の SMTP サーバに 25 番ポートで接続ができる環境
root@9c33e656a290:/# telnet gmail-smtp-in.l.google.com 25
Trying 64.233.189.27...
Connected to gmail-smtp-in.l.google.com.
Escape character is '^]'.
220 mx.google.com ESMTP c6-20020a63da06000000b004a6549b92afsi16596801pgh.699 - gsmtp

quit
221 2.0.0 closing connection c6-20020a63da06000000b004a6549b92afsi16596801pgh.699 - gsmtp
Connection closed by foreign host.

root@9c33e656a290:/#

この場合、以下のようなエラーとなっているかもしれない.

root@9c33e656a290:/# cat /var/log/mail.log
...
Jan 12 06:03:13 mail postfix/pickup[3778]: 26F004A30E0: uid=0 from=<root>
Jan 12 06:03:13 mail postfix/cleanup[3803]: 26F004A30E0: message-id=<[email protected]>
Jan 12 06:03:13 mail postfix/qmgr[3661]: 26F004A30E0: from=<[email protected]>, size=313, nrcpt=1 (queue active)
Jan 12 06:03:15 mail postfix/smtp[3806]: 26F004A30E0: to=<アカウント名@gmail.com>, relay=gmail-smtp-in.l.google.com[64.233.189.26]:25, delay=33, delays=31/0/1/1.4, dsn=5.7.25, status=bounced (host gmail-smtp-in.l.google.com[64.233.189.26] said: 550-5.7.25 [XXX.XXX.XXX.XXX] The IP address sending this message does not have a PTR 550-5.7.25 record setup, or the corresponding forward DNS entry does not point 550-5.7.25 to the sending IP. As a policy, Gmail does not accept messages from 550-5.7.25 IPs with missing PTR records. Please visit 550-5.7.25  https://support.google.com/mail/answer/81126#ip-practices for more 550 5.7.25 information. q20-20020a170902b11400b00187073496b4si16122130plr.136 - gsmtp (in reply to end of DATA command))
Jan 12 06:03:15 mail postfix/cleanup[3803]: 97A834A30E1: message-id=<[email protected]>
Jan 12 06:03:15 mail postfix/bounce[3807]: 26F004A30E0: sender non-delivery notification: 97A834A30E1
Jan 12 06:03:15 mail postfix/qmgr[3661]: 97A834A30E1: from=<>, size=3231, nrcpt=1 (queue active)
Jan 12 06:03:15 mail postfix/qmgr[3661]: 26F004A30E0: removed
Jan 12 06:03:17 mail postfix/smtp[3806]: 97A834A30E1: to=<[email protected]>, relay=gmr-smtp-in.l.google.com[142.251.8.14]:25, delay=2.2, delays=0.01/0/1.8/0.3, dsn=5.1.1, status=bounced (host gmr-smtp-in.l.google.com[142.251.8.14] said: 550-5.1.1 The email account that you tried to reach does not exist. Please try 550-5.1.1 double-checking the recipient's email address for typos or 550-5.1.1 unnecessary spaces. Learn more at 550 5.1.1  https://support.google.com/mail/?p=NoSuchUser y7-20020a5e8347000000b006deecdea1dfsi963539iom.2 - gsmtp (in reply to RCPT TO command))
Jan 12 06:03:17 mail postfix/qmgr[3661]: 97A834A30E1: removed
root@9c33e656a290:/#
root@9c33e656a290:/# cat /var/log/mail.log
...
Jan 12 06:01:57 mail postfix/pickup[3778]: 5DB524A30E0: uid=0 from=<root>
Jan 12 06:01:57 mail postfix/cleanup[3803]: 5DB524A30E0: message-id=<[email protected]>
Jan 12 06:01:57 mail postfix/qmgr[3661]: 5DB524A30E0: from=<[email protected]>, size=313, nrcpt=1 (queue active)
Jan 12 06:01:58 mail postfix/smtp[3806]: 5DB524A30E0: to=<アカウント名@gmail.com>, relay=gmail-smtp-in.l.google.com[64.233.189.26]:25, delay=27, delays=26/0/0.69/0.51, dsn=5.7.26, status=bounced (host gmail-smtp-in.l.google.com[64.233.189.26] said: 550-5.7.26 This message does not pass authentication checks (SPF and DKIM both 550-5.7.26 do not pass). SPF check for [annpin.com] does not pass with ip: 550-5.7.26 [XXX.XXX.XXX.XXX].To best protect our users from spam, the message has 550-5.7.26 been blocked. Please visit 550-5.7.26  https://support.google.com/mail/answer/81126#authentication for more 550 5.7.26 information. w5-20020a631605000000b004b32a701c8csi10890892pgl.763 - gsmtp (in reply to end of DATA command))
Jan 12 06:01:58 mail postfix/cleanup[3803]: 93DCD4A30E1: message-id=<[email protected]>
Jan 12 06:01:58 mail postfix/bounce[3807]: 5DB524A30E0: sender non-delivery notification: 93DCD4A30E1
Jan 12 06:01:58 mail postfix/qmgr[3661]: 93DCD4A30E1: from=<>, size=3181, nrcpt=1 (queue active)
Jan 12 06:01:58 mail postfix/qmgr[3661]: 5DB524A30E0: removed
Jan 12 06:02:00 mail postfix/smtp[3806]: 93DCD4A30E1: to=<[email protected]>, relay=gmr-smtp-in.l.google.com[142.251.8.14]:25, delay=1.6, delays=0.01/0/1.3/0.23, dsn=5.1.1, status=bounced (host gmr-smtp-in.l.google.com[142.251.8.14] said: 550-5.1.1 The email account that you tried to reach does not exist. Please try 550-5.1.1 double-checking the recipient's email address for typos or 550-5.1.1 unnecessary spaces. Learn more at 550 5.1.1  https://support.google.com/mail/?p=NoSuchUser w10-20020a17090abc0a00b0022673858f16si541963pjr.1 - gsmtp (in reply to RCPT TO command))
Jan 12 06:02:00 mail postfix/qmgr[3661]: 93DCD4A30E1: removed
root@9c33e656a290:/#

25 番ポートがブロックされていない環境の場合、 Gmail 側のセキュリティ強化の影響で、DNS 上に SPF レコード の登録が無いドメインからのメールに対しては 550-5.7.26 エラーが発生するようになっているようだ.

解決策としては https://agohack.com/avoid-being-spammail-with-spf/ などを参考にすると良いだろう.