mattintosh note

どこかのエンジニアモドキの備忘録

DebianでPostfixを構築してGmailを送る

Elasticsearch で収集している VTuber の情報を定期的にはてなブログに自動投稿しようかなと思ったのでメールサーバを構築した。久しぶりにやって忘れていたのでメモっておくことにする。CentOS の情報は多いけど Debian 系は少ない。

環境

PRETTY_NAME="Debian GNU/Linux 10 (buster)"
NAME="Debian GNU/Linux"
VERSION_ID="10"
VERSION="10 (buster)"
VERSION_CODENAME=buster
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"

Postfix の設定

必要なパッケージをインストールする。

  • postfix
  • sasl2-bin
  • bsd-mailx
  • nkf(メール表題の日本語文字化け回避用)

Terminal

apt install postfix sasl2-bin bsd-mailx

Google のアカウントで二段階認証不要のアプリ用パスワードを作成しておく。16 文字のパスワードを発行される。

SASL 用のパスワードファイルを作成する。ユーザ名 foo、アプリケーション用のパスワードが aaaaaaaaaaaaaaaa の場合は下記のような書式になる。/etc/postfixsasl というディレクトリが出来ているのでその中でもいいと思う。

/etc/postfix/sasl_passwd

[smtp.gmail.com]:587 foo@gmail.com:aaaaaaaaaaaaaaaa

平文で書いてあるのでパーミッションを変更しておく。

Terminal

chmod 0600 /etc/postfix/sasl_passwd

postmap コマンドで Postfix ルックアップテーブルを作成する。sasl_passwd.db のようなファイルが作成される。

Terminal

postmap /etc/postfix/sasl_passwd

main.cf の設定

/etc/postfix/main.cf に設定を追加する。最低限下記を追加しておけばメールの送信が出来るようになる。

/etc/postfix/main.cf

relayhost = [smtp.gmail.com]:587
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_sasl_tls_security_options = noanonymous
smtp_tls_security_level = encrypt

デフォルトからの差分は下記の通り

--- /dev/fd/63  2019-11-17 15:11:02.659286299 +0900
+++ main.cf     2019-11-17 15:10:59.619368408 +0900
@@ -36,9 +36,13 @@
 alias_maps = hash:/etc/aliases
 alias_database = hash:/etc/aliases
 mydestination = $myhostname, localhost, localhost.localdomain, , localhost
-relayhost =
+relayhost = [smtp.gmail.com]:587
 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
+smtp_sasl_auth_enable = yes
+smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
+smtp_sasl_tls_security_options = noanonymous
+smtp_tls_security_level = encrypt

Postfix を再起動(もしくは設定ファイルを再読み込み)する。

Terminal

systemctl restart postfix

Postfix パラメータの詳細

デフォルト値は postconf -d で確認することも出来る。

man 5 postconf

smtp_sasl_auth_enable (default: no)
       Enable SASL authentication in the Postfix SMTP  client.   By  default,
       the Postfix SMTP client uses no authentication.

       Example:

       smtp_sasl_auth_enable = yes

smtp_sasl_mechanism_filter (default: empty)
       If  non-empty,  a  Postfix  SMTP  client  filter  for  the remote SMTP
       server's list of offered SASL mechanisms.  Different client and server
       implementations may support different mechanism lists; by default, the
       Postfix  SMTP  client  will  use  the   intersection   of   the   two.
       smtp_sasl_mechanism_filter  specifies an optional third mechanism list
       to intersect with.

       Specify mechanism names, "/file/name" patterns or "type:table"  lookup
       tables.  The  right-hand  side  result  from  "type:table"  lookups is
       ignored. Specify "!pattern" to exclude a mechanism name from the list.
       The  form  "!/file/name"  is supported only in Postfix version 2.4 and
       later.

       This feature is available in Postfix 2.2 and later.

       Examples:

       smtp_sasl_mechanism_filter = plain, login
       smtp_sasl_mechanism_filter = /etc/postfix/smtp_mechs
       smtp_sasl_mechanism_filter = !gssapi, !login, static:rest

smtp_sasl_password_maps (default: empty)
       Optional Postfix SMTP client lookup tables with one  username:password
       entry  per  sender,  remote  hostname  or  next-hop domain. Per-sender
       lookup is done only when sender-dependent authentication  is  enabled.
       If  no  username:password entry is found, then the Postfix SMTP client
       will not attempt to authenticate to the remote host.

       The Postfix SMTP client opens the lookup table before going to  chroot
       jail, so you can leave the password file in /etc/postfix.

       Specify  zero  or  more "type:name" lookup tables, separated by white‐
       space or comma. Tables will be searched in the specified order until a
       match is found.

smtp_sasl_security_options (default: noplaintext, noanonymous)
       Postfix SMTP client SASL security options; as of Postfix 2.3 the  list
       of  available  features depends on the SASL client implementation that
       is selected with smtp_sasl_type.

       The following security features are defined for the cyrus client  SASL
       implementation:

       Specify zero or more of the following:

       noplaintext
              Disallow methods that use plaintext passwords.

       noactive
              Disallow methods subject to active (non-dictionary) attack.

       nodictionary
              Disallow methods subject to passive (dictionary) attack.

       noanonymous
              Disallow methods that allow anonymous authentication.

       mutual_auth
              Only  allow  methods  that  provide  mutual authentication (not
              available with SASL version 1).

       Example:

       smtp_sasl_security_options = noplaintext

smtp_sasl_tls_security_options (default: $smtp_sasl_security_options)
       The SASL authentication security options that the Postfix SMTP  client
       uses for TLS encrypted SMTP sessions.

       This feature is available in Postfix 2.2 and later.

smtp_tls_security_level (default: empty)
       The default SMTP TLS security level for the Postfix SMTP client; when a
       non-empty  value  is  specified, this overrides the obsolete parameters
       smtp_use_tls, smtp_enforce_tls, and smtp_tls_enforce_peername.

       Specify one of the following security levels:

       none
              No TLS. TLS will not be used unless enabled for specific  desti‐
              nations via smtp_tls_policy_maps.

       may
              Opportunistic  TLS.  Use  TLS if this is supported by the remote
              SMTP server, otherwise use plaintext. Since sending in the clear
              is  acceptable,  demanding  stronger  than  default TLS security
              merely reduces  interoperability.   The  "smtp_tls_ciphers"  and
              "smtp_tls_protocols"  (Postfix  >= 2.6) configuration parameters
              provide control over the protocols and cipher  grade  used  with
              opportunistic  TLS.  With earlier releases the opportunistic TLS
              cipher grade is always "export" and no protocols  are  disabled.
              When  TLS  handshakes  fail,  the connection is retried with TLS
              disabled.  This allows mail delivery to sites with  non-interop‐
              erable TLS implementations.

       encrypt
              Mandatory  TLS  encryption. Since a minimum level of security is
              intended, it is reasonable to  be  specific  about  sufficiently
              secure protocol versions and ciphers. At this security level and
              higher, the main.cf parameters smtp_tls_mandatory_protocols  and
              smtp_tls_mandatory_ciphers specify the TLS protocols and minimum
              cipher grade which the administrator considers secure enough for
              mandatory  encrypted  sessions.  This  security  level is not an
              appropriate default for systems delivering mail to the Internet.

       dane
              省略

       dane-only
              省略

       fingerprint
              省略

       verify
              省略

       secure
              省略

       Examples:

       # No TLS. Formerly: smtp_use_tls=no and smtp_enforce_tls=no.
       smtp_tls_security_level = none

       # Opportunistic TLS.
       smtp_tls_security_level = may
       # Postfix >= 2.6:
       # Do not tweak opportunistic ciphers or protocol unless it is essential
       # to do so (if a security vulnerability is found in the SSL library that
       # can be mitigated by disabling a particular protocol or raising the
       # cipher grade from "export" to "low" or "medium").
       smtp_tls_ciphers = export
       smtp_tls_protocols = !SSLv2, !SSLv3

       # Mandatory (high-grade) TLS encryption.
       smtp_tls_security_level = encrypt
       smtp_tls_mandatory_ciphers = high

       以下略

トラブルシュート

smtp_sasl_auth_enable = yes

これが無いと Authentication Required. で失敗する。

Nov 16 08:10:23 debian postfix/smtp[5891]: 49F92409EE: to=foo@gmail.com, relay=smtp.gmail.com[74.125.204.108]:587, delay=1, delays=0.01/0/0.82/0.17, dsn=5.5.1, status=bounced (host smtp.gmail.com[74.125.204.108] said: 530-5.5.1 Authentication Required. Learn more at 530 5.5.1 https://support.google.com/mail/?p=WantAuthError 82sm14466130pfa.115 - gsmtp (in reply to MAIL FROM command))

smtp_sasl_password_maps = hash:/path/to/file

これが無いと specify a password table via the `smtp_sasl_password_maps' configuration parameter で失敗する。

Nov 16 08:17:46 debian postfix/smtp[6345]: fatal: specify a password table via the `smtp_sasl_password_maps' configuration parameter

smtp_sasl_tls_security_options = noanonymous

デフォルトの noplaintext, noanonymous だと弾かれてしまうので noplaintext を外して noanonymous だけにする。

Nov 16 08:04:32 debian postfix/smtp[5265]: warning: SASL authentication failure: No worthy mechs found Nov 16 08:04:32 debian postfix/smtp[5265]: 6D638409F6: SASL authentication failed; cannot authenticate to server smtp.gmail.com[108.177.97.108]: no mechanism available Nov 16 08:04:32 debian postfix/smtp[5265]: connect to smtp.gmail.com[2404:6800:4008:c00::6c]:587: Network is unreachable

smtp_tls_security_level = encrypt

デフォルトが empty なので Must issue a STARTTLS command first. で失敗する。encrypt ではなく may でも動くがこちらは TLS 接続に失敗した時にプレーンテキストを使うようなので encrypt にした。

Nov 16 08:12:56 debian postfix/smtp[6109]: 991C44085B: to=foo@gmail.com, relay=smtp.gmail.com[74.125.204.108]:587, delay=0.65, delays=0.05/0.01/0.41/0.17, dsn=5.7.0, status=bounced (host smtp.gmail.com[74.125.204.108] said: 530 5.7.0 Must issue a STARTTLS command first. y6sm12524933pfm.12 - gsmtp (in reply to MAIL FROM command))

メールの送信

とりあえず適当にメールを送ってみる。

Terminal

echo "World" | mail -s "Hello" 宛先メールアドレス

特に問題無かったのではてなブログにメール投稿する方法を調べると投稿用と下書き用のメールアドレスで分かれているらしい。

help.hatenablog.com

下書き用のメールアドレスにメールを送ってみると何故かタイトルの日本語が文字化けする。調べてみるとタイトルは ISO-2022-JP で出力しなきゃいけないらしい。nkf コマンドを使ってエンコードする。入力と出力でオプションの大小文字が違う。

nkf --help

Usage:  nkf -[flags] [--] [in file] .. [out file for -O flag]
 j/s/e/w  Specify output encoding ISO-2022-JP, Shift_JIS, EUC-JP
          UTF options is -w[8[0],{16,32}[{B,L}[0]]]
 J/S/E/W  Specify input encoding ISO-2022-JP, Shift_JIS, EUC-JP
          UTF option is -W[8,[16,32][B,L]]
 m[BQSN0] MIME decode [B:base64,Q:quoted,S:strict,N:nonstrict,0:no decode]
 M[BQ]    MIME encode [B:base64 Q:quoted]
 f/F      Folding: -f60 or -f or -f60-10 (fold margin 10) F preserve nl
 Z[0-4]   Default/0: Convert JISX0208 Alphabet to ASCII
          1: Kankaku to one space  2: to two spaces  3: HTML Entity
          4: JISX0208 Katakana to JISX0201 Katakana
 X,x      Convert Halfwidth Katakana to Fullwidth or preserve it
 O        Output to File (DEFAULT 'nkf.out')
 L[uwm]   Line mode u:LF w:CRLF m:CR (DEFAULT noconversion)
 --ic=<encoding>        Specify the input encoding
 --oc=<encoding>        Specify the output encoding
 --hiragana --katakana  Hiragana/Katakana Conversion
 --katakana-hiragana    Converts each other
 --{cap, url}-input     Convert hex after ':' or '%'
 --numchar-input        Convert Unicode Character Reference
 --fb-{skip, html, xml, perl, java, subchar}
                        Specify unassigned character's replacement
 --in-place[=SUF]       Overwrite original files
 --overwrite[=SUF]      Preserve timestamp of original files
 -g --guess             Guess the input code
 -v --version           Print the version
 --help/-V              Print this help / configuration
Network Kanji Filter Version 2.1.5 (2018-12-15) 
Copyright (C) 1987, FUJITSU LTD. (I.Ichikawa).
Copyright (C) 1996-2018, The nkf Project.

ja_JP.UTF-8 とかなら入力に -W(UTF)付けなくてもいいみたいだけど一応付けておく。

Shell-Session

root@debian:~# echo "タイトル" | nkf -MWj
=?ISO-2022-JP?B?GyRCJT8lJCVIJWsbKEI=?=

あとはこれを Cron に組み込んではてなブログの投稿用メールアドレスに送れば自動投稿が出来るようになる。

結果

VTuber の一週間の再生回数を土曜日の朝に自動投稿するようにした。週末はここから流行りの VTuber のチャンネルでも観てゆっくり過ごしたい。

mattintosh.hatenablog.com