Pythonでマルチパートメールを送る方法をブログにしました。しかし、前回の記事はファイルからテンプレートを取得していないので、マルチパートメールを実質運用できません。今回はjinja2を使用してファイルからテンプレートを取得することで実運用できるようにします。
環境
- Python
- 3.12.3
- jinja2
- 3.1.3
- MailHog
- v1.0.1
事前条件
前回記事をベースに、jinja2でファイルのテンプレートを取得できるようにする。
対応
テンプレートを格納する
HTMLファイルとテキストファイルを配備します。
今回の例では次のディレクトリにファイルを配備します。
- src/resources/templates/signin.html
- src/resources/templates/signin.txt
また、今回のテンプレートにはname
という変数を用意しています。
# src/resources/templates/signin.txt Welcome to our platform, {{ name }}!
テンプレート読み込む
jinja2
を用いてテンプレートを読み込みます。今回の例ではsrc/resources/templates
にメールテンプレートを配備しているので、FileSystemLoader
にディレクトリを渡します。また、レンダリングする際にパラメータが不足した時にエラーとなるようにEnvironment
にundefined
を定義します。発生したエラーは次のようなものが発生します。
jinja2.exceptions.UndefinedError: 'name' is undefined
次のコードを元に、HTMLメールとテキストメールのテンプレートを読み込むようにします。
from jinja2 import Template, Environment, FileSystemLoader, StrictUndefined @classmethod def get_templates(cls, path: str): file_loader = FileSystemLoader("src/resources/templates") env = Environment(loader=file_loader, undefined=StrictUndefined) template_text = env.get_template(f"{path}.txt") template_html = env.get_template(f"{path}.html") return template_text, template_html
ファイルレンダリング
読み込んだテンプレートに変数を埋め込んで、メール送信できる文字列に変換します。
@classmethod def build_body(cls, path: str, params={}): text, html = cls.get_templates(path) return text.render(**params), html.render(**params)
メソッドの呼び出し
ファイル名、パラメータのキーと値を渡せばファイルからテンプレートを読めます。
body_text, body_html = Mailer.build_body("signin", params={"name": "NAME"})
前回の記事と合わせて次のようなメソッドになります。
@classmethod def send(cls) -> None: sender = "no-reply@example.com" receiver = "1@example.com" subject = "Python SMTP Mail Subject" body_text, body_html = Mailer.build_body("signin", params={"name": "NAME"}) msg = EmailMessage() msg.set_content(body_text) msg.add_alternative(body_html, subtype="html") msg["Subject"] = subject msg["From"] = sender msg["To"] = receiver try: with SMTP(host=cls.host, port=cls.port) as smtp: smtp.send_message(msg) except Exception as e: print(f"Failed to send email. Error {str(e)}") raise e
ソースコード
今回のテスト用に少々テストコードを変更しています。
- https://github.com/hirotoKirimaru/fastapi-practice/blob/379e5fad0d4005cb874e3439e614428315c2100e/src/helper/mailer.py#L7
- https://github.com/hirotoKirimaru/fastapi-practice/blob/379e5fad0d4005cb874e3439e614428315c2100e/tests/helpers/test_mailer.py#L4
終わりに
取り急ぎ本番でも運用できる状態になったと思います。他にもjinja2には良さそうなオプションがあるので色々と素振りしたいですね。