ラズパイからのお知らせを、メールでも受けられるようにします。メールは、スマホでも PC でも読めて、あとから見返したり、ほかの人に転送したりしやすいのがよいところです。声や LINE ほどすぐには気づかないので、「急ぎではないけれど、記録として残したいお知らせ」に向いています。
この記事では、Python の標準ライブラリ(smtplib)だけで、レンタルサーバーなどのメールアカウントから、自分あてにメールを送る仕組みを作ります。
この記事の前にできていること
- ラズパイに PC から SSH で接続できる(第 3 回まで)
- 送るためのメールアカウント(レンタルサーバーのメールなど)。SMTP のサーバーの名前・ポート・ユーザー名・パスワードが分かっていること
この記事でできるようになること
- ラズパイから、自分あてにメールを送る
- 声や LINE のお知らせと同じきっかけで、メールにも送る
先に知っておくこと
- 通知用のアカウントを分けるのがおすすめ:ふだん使いのアカウントのパスワードをラズパイに置くより、通知を送るだけのアカウントを 1 つ作るほうが安全です(万一パスワードが漏れても、被害がそのアカウントだけで済みます)。
- Gmail から送るときは「アプリ パスワード」:Gmail の SMTP を使うときは、ふだんのパスワードではなく、Google のアカウントで作るアプリ パスワードを使います(2 段階認証が必要です)。
- 送り先は自分だけ:通知のメールを、ほかの人のアドレスに送らないようにします。自分あてなら、迷惑メールと判断されにくくもなります。
手順 A:スクリプトと設定を置く
ラズパイの ~/notify に、次の 2 つのファイルを作ります。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
ラズパイから、自分あてにメールで知らせる(SMTP・Python の標準ライブラリだけ)
使い方:python3 mail_send.py "件名" "本文"
ほかの Python からは:import mail_send; mail_send.send("件名", "本文")
設定は同じフォルダの mail_send.ini(送るメールアカウント・送り先)。
"""
import configparser
import os
import smtplib
import ssl
import sys
from email.message import EmailMessage
from email.utils import formatdate, make_msgid
HERE = os.path.dirname(os.path.abspath(__file__))
NEED = ("host", "user", "password", "from", "to")
def load():
cfg = configparser.ConfigParser(interpolation=None) # パスワードの % をそのまま読む
path = os.path.join(HERE, "mail_send.ini")
try:
if not cfg.read(path, encoding="utf-8") or not cfg.has_section("smtp"):
raise RuntimeError("設定ファイル mail_send.ini([smtp])がありません")
c = cfg["smtp"]
missing = [k for k in NEED if not c.get(k, "").strip()]
port = c.getint("port", fallback=465)
except configparser.Error as e:
raise RuntimeError("mail_send.ini の書き方がちがいます(%s)" % e.__class__.__name__)
except ValueError:
raise RuntimeError("mail_send.ini の port が数字になっていません")
if missing:
raise RuntimeError("mail_send.ini に %s が入っていません" % "・".join(missing))
return c, port
def send(subject, body):
"""送れたら True。送り先は mail_send.ini の to(自分のアドレスだけにしておく)"""
try:
c, port = load()
except RuntimeError as e:
print("送れませんでした:%s" % e, file=sys.stderr)
return False
msg = EmailMessage()
msg["Subject"] = subject[:200]
msg["From"] = c["from"]
msg["To"] = c["to"]
msg["Date"] = formatdate(localtime=True)
msg["Message-ID"] = make_msgid(domain=c["from"].rpartition("@")[2] or None)
msg.set_content(body)
try:
if port == 465: # はじめから暗号化(SMTPS)
with smtplib.SMTP_SSL(c["host"], port, context=ssl.create_default_context(), timeout=20) as s:
s.login(c["user"], c["password"])
s.send_message(msg)
else: # 587:接続してから暗号化(STARTTLS)
with smtplib.SMTP(c["host"], port, timeout=20) as s:
s.starttls(context=ssl.create_default_context())
s.login(c["user"], c["password"])
s.send_message(msg)
return True
except (smtplib.SMTPException, OSError) as e:
# パスワードは表示しない
print("送れませんでした:%s" % e.__class__.__name__, file=sys.stderr)
return False
if __name__ == "__main__":
if len(sys.argv) < 3:
print(__doc__)
sys.exit(1)
if send(sys.argv[1], sys.argv[2]):
print("送った")
sys.exit(0)
sys.exit(2)
[smtp]
host = smtp.example.com
port = 465
user = notify@example.com
password = (メールアカウントのパスワード)
from = notify@example.com
to = me@example.com
chmod 600 ~/notify/mail_send.ini
書き方と役目
port:465 ははじめから暗号化(SMTPS)、587 は接続してから暗号化(STARTTLS)。どちらを使うかは、メールアカウントの説明のページに書いてありますinterpolation=None:パスワードに%が入っていても、そのまま読む- パスワードは表示しない:送れなかったときに出すのは、エラーの種類の名前だけ
Message-ID・Date:メールの決まりの欄。これがないと迷惑メールと判断されやすい- 必要な値を先に確認する:
host・user・password・from・toが空のときや、portが数字でないときは、送らずに理由を出して止まる - 送れたら「送った」:コマンドで動かしたときだけ出す。ほかの Python から
send()を呼んだときは、何も出さずに True を返す
手順 B:送ってみる
cd ~/notify
python3 mail_send.py "[ラズパイ] テスト" "ラズパイからの通知のテストです。"
家で送ってみた結果
- 送り元はレンタルサーバーのメール(465 番・はじめから暗号化)で、送り先は自分のアドレス
- 件名「[ラズパイ] メールの通知のテスト」・本文に送った時刻を書いて、1 通送った
- スクリプトは「送った」で終わり、自分のメールの受信箱に届いた
設定ファイルがないときや、必要な値が入っていないときは、送らずに理由を出して止まります。パスワードがまちがっているときは、「送れませんでした:SMTPAuthenticationError」のように、エラーの種類の名前だけを出して止まります。
送れませんでした:設定ファイル mail_send.ini([smtp])がありません
声や LINE と一緒に使う
売れたメールを声で知らせる仕組みで声を置いている所や、LINE で知らせる仕組みと同じように、1 行足せばメールにも届きます。
import mail_send
mail_send.send("[ラズパイ] バックアップに失敗しました", "db_backup.sh が失敗しました。backup.log を見てください。")
件名の頭を [ラズパイ] のように決めておくと、メールの振り分けの決まりで、通知だけをまとめて見られます。
まとめ
Python の標準ライブラリだけで、ラズパイから自分あてにメールで知らせる仕組みを作りました。すぐに気づく声や LINE と、あとから見返せるメールを組み合わせると、お知らせの漏れが減ります。
次に読む