みかんのゆるふわ技術ブログ

Raspberry PiやIoT関係のことを書き残していきます

Raspberry PiにPostfixを入れてコマンドラインからGmail経由でメールを送ろう

Raspberry Piで何かイベントが起きた時に外部にメールで通知できると便利ですよね。 今回は、有名なメールサーバーのPostfixをRaspberry Piへインストールし、Gmailへの中継用に使うことで、外部にメール送信してみました。

ちなみにここではGmailを使っていますが、他のメールサービスも同じように使えます。ただし、最初のセクションのGmail側の設定は不要だったり、別の方法があったりしりますので、利用したいメールサービスのマニュアルに従ってください。

Gmail側の設定

Gmailはセキュリティにとても気を使っており、Googleが定めるセキュリティ標準(OAuth2.0の使用など)を満たしたアプリ以外からのアクセスはブロックされます。Raspberry Piのような画面のないデバイスからOAuth2.0なども使わずにGmailにアクセスするには、準備が必要です。

2つの選択肢がありますので、どちらかを実行してください。

アプリパスワードを発行する

アプリパスワードを使用すると、2 段階認証プロセスに対応していないデバイス上のアプリからGoogle アカウントにログインできるようになります。アプリパスワードを利用するには、あらかじめ2段階認証を有効にしておく必要があります。以下のGoogleアカウントのページから設定できます。

myaccount.google.com

Googleアカウントのページにログインしたら、メニューからセキュリティを選びます。

f:id:kimura_khs:20200902214524p:plain:w480

2段階認証を有効にしていると、アプリパスワードというメニューが見えるはずです。 2段階認証を使っていない場合は、ここから有効にできます。

f:id:kimura_khs:20200902214534p:plain:w480

アプリパスワードのメニューを開くと、このような画面が出ます。「アプリ パスワードを生成するアプリとデバイスを選択してください」のところで、それぞれ「メール」「その他」を選びます。名前の入力欄が出ますので、何かわかりやすい名前を付けてください。私はraspberrypiとしました。

f:id:kimura_khs:20200902214542p:plain:w480

生成ボタンを押すと、このように16文字のパスワードが出てきます。4文字ごとにスペースが空いていますが、空白(スペース)文字は入れずにアルファベット16文字を続けたものがパスワードになります。

このパスワードは1度しか表示されませんが、メモしたりせず、Raspberry Piに入力した後は閉じてしまいましょう。 もし忘れた場合は、発行済みパスワードを無効化して再度新しく発行し直してください。

なお、このスクリーンショットのパスワードは私が生成したものですが、既に無効になっていますのでご安心(?)ください。

f:id:kimura_khs:20200902214553p:plain:w480

生成したパスワードはこのように一覧で見られます。横のゴミ箱アイコンをクリックするとパスワードを無効化できます。

安全性の低いアプリからのアクセスを有効にする

2段階認証を有効にしていない場合、もう1つの手段として「安全性の低いアプリからのアクセスを有効にする」という方法があります。

f:id:kimura_khs:20200902220548p:plain

このメニューからアクセスを有効化(非推奨)を選んで有効化できます。 これをすると、どんなアプリからも「メールアドレス」と「パスワード」でログインできるようになるのだろうと思います。 セキュリティは低下しますので、よく考えて行ってください。

Postfixのインストール・設定

インストール

まずはメールサーバーのPostfixをインストールします。 Gmailの場合送信にTLSを使うためlibsasl2-modulesも必要なようです。

$ sudo apt install postfix libsasl2-modules

Postfixの設定

Postfixの設定ファイルは/etc/postfix/main.cfです。このファイルをvimなどで編集します。 まず、外部からのメール中継要求を受け付けないようにします。

inet_interfaces = loopback-only  # 変更

続いて、Gmailを中継サーバーに設定します。Gmailのメール送信サーバーはsmtp.gmail.comの587番ポートです。

relayhost = [smtp.gmail.com]:587  # 変更

続いて、SMTP認証やTLSに関する設定をします。ファイルの末尾に次の設定を追加します。

# 追加
smtp_sasl_auth_enable = yes
smtp_tls_security_level = encrypt
smtp_sasl_security_options = noanonymous
smtp_sasl_password_maps = hash:/etc/postfix/sasl/sasl_passwd
smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt

これでこのファイルを保存します。

Gmail認証の設定

Gmailにメール送信してもらうには、アカウント情報が必要です。 /etc/postfix/sasl/sasl_passwdというファイルを新規作成し、アカウント情報を書き込みます。 メールアドレスがexample@gmail.com、パスワードがpasswordの場合の例はこのようになります。

[smtp.gmail.com]:587 example@gmail.com:password

このファイルはこの1行だけでOKです。

アプリパスワードを発行した場合はアプリパスワードを、そうでない場合(安全性の低いアプリからのアクセスを有効にした場合)はGmailアカウントのパスワードを記入してください。

パスワードを平文で書くことになるので、流出には十分注意してください。 ファイルを保存したら、これをPostfixが扱える形式に変換します。postmapというコマンドを使います。

$ sudo postmap /etc/postfix/sasl/sasl_passwd
$ sudo rm /etc/postfix/sasl/sasl_passwd

1行目を実行すると、/etc/postfix/sasl/sasl_passwd.dbというファイルができます。 元ファイルは不要なので、2行目で削除します。

ちなみにこのdbファイルは暗号化されているわけではありませんので、流出には十分注意してください。

設定を反映

以上で設定は終わりです。Postfixを再起動して設定を反映します。

$ sudo systemctl restart postfix

動作確認

コマンドライン編

Postfixにはsendmailというコマンドが付属しており、メールの送信ができます。 昔デファクトスタンダードだったメールサーバーsendmailのコマンドと互換になっているそうです。

$ sendmail example@gmail.com
Subject: This is a test mail
Hello from Raspberry Pi
.

あて先メールアドレスをsendmailコマンドの引数にして起動します。 起動すると何もメッセージも出ず入力待ちになるので、1行目にSubject:と書いてからメールのタイトルを、2行目以降にメールの本文を書きます。書き終わったら次の行に.(ピリオド)のみ書いてEnterを押します。最後のピリオドは送信されませんのでご安心ください。

うまくメールが届きましたでしょうか?届かなかった場合は後述のトラブルシューティングを見てくださいね。

Python編

Pythonに標準で付属しているsmtplibを使ってメール送信ができます。次のようにします。

import smtplib
 
fromaddr = "from@gmail.com"
toaddr = "to@gmail.com"
subject = "This is a test mail"
body = """\
Hello from Raspberry Pi!
 
This is a test mail.
"""
 
server = smtplib.SMTP('localhost')
msg = "Subject: {}\n{}".format(subject, body)
server.sendmail(fromaddr, toaddr, msg)
server.quit()

これをmailtest.pyなどとファイルに保存して、実行します。

$ python mailtest.py

同じように送信できるはずです。

トラブルシューティング

実は私は上の手順ではメール送信ができませんでした。メールが送れないな?と思ったら、ログを見てみましょう。 デフォルトでは/var/log/syslogにログが書かれています。postfixで検索するとよいでしょう。

Network is unreachable

私の場合、こんなログが出ていました。

Sep  2 11:29:54 raspberrypi postfix/smtp[1620]: connect to smtp.gmail.com[2404:6800:4008:c04::6d]:587: Network is unreachable

smtp.gmail.comに繋がらない(Network is unreachable)というログです。 よく見ると、アドレスがIPv6アドレスです。実は私の家のインターネット回線は未だにIPv6に対応していないので、これでは繋がりません。

このような場合は、強制的にIPv4を使います。Postfixの設定ファイル/etc/postfix/main.cfの、次の行を変更します。

inet_protocols = ipv4     # 変更

これでPostfixを再起動すると、IPv4が使われて、メールが送れるようになりました。

このように、環境依存のエラーが出る場合があります。エラーログを見て検索するなどして問題を解決し、メールが送れるようにがんばってください!

f:id:kimura_khs:20200902223136j:plain