FastAPIでメールフォームを作ってみた件

今日はFASTAPIを用いてメールフォームを作成していて、やっとこさ動いたので、アウトプットする。

 

参考記事

STEP①利用するモジュールをインポートしていく

今回のメールフォーム作成では「FastAPI-Mail」モジュールを用いて作成する。

インポートの仕方は下記を参照。

 from fastapi_mail import MessageSchema, FastMail, ConnectionConfig

仮想環境にインストールしていない人は、インストールしてね。

 pip install fastapi-mail

 

ここで「FastAPI-Mail」、「MessageSchema」、「FastMail」、「ConnctionConfig」それぞれの機能と使い方について理解しておこう。

 

利用するモジュールの機能

  • FastAPI-Mail :電子メールを簡単に行うことができるモジュール 
    • 電子メールの送信機能
      • SMTPサーバーを設定し、送信が可能。併せて宛先・件名・本文・添付ファイルなど、メールの内容の指定ができる
    • メールテンプレート機能
      • メールの本文をHTML形式で作成する機能
    • メールの非同期送信
      • 非同期タスクとしてメールの送信が可能
    • エラーに対する処理機能
      • SMTPサーバーへの接続エラー、メールの送信エラーの検出。またエラー内容の取得が可能。
      • エラー時に代替アクションの提供も可能。
  • MessageSchema :送信されるメールの詳細情報を設定する
  • ConnectionConfig:SMTPサーバーの接続設定をするためのクラス。
  • FastMail:メース送信に関する機能を提供するクラス

利用するモジュールの使い方

  • fastapi_mail
    1. インストール
    2. SMTP接続情報の設定
    3. FastMailオブジェクトの初期化
  • ConnectionConfig
    • MAIL_USERNAME:SMTPサーバー接続時のユーザー名
    • MAIL_PASSWORD:SMTPサーバー接続時のパスワード
    • MAIL_FROM:送信元アドレスの設定
    • MAIL_PORT:SMTPサーバーのポート番号を指定
    • MAIL_SERVER:SMTPのサーバー名を入力
    • MAIL_TLSTLSを使用するか
    • MAIL_SSLSSLを使用するか
  • MesseageSchema (MessageSchemaオブジェクトを生成し、オブジェクト内にメールの情報を記載する
    • subject:メール件名
    • recipients:メールの送り先アドレスを指定
    • body:メールの本文を指定
    • plain_text:メールの本文をプレーンテキスト形式で指定する場合に使用。bodyとは別に指定可能。
    • html:メールの本文をHTML形式で指定する場合に使用。bodyとは別に指定可能
    • cc:ccアドレスの指定
    • bccbccアドレスの指定
    • attachments:メールに添付するファイルのリストを指定

 

 メールフォーム作成の流れ

  1. fastapi_emailモジュールから、MesseageSchemaとFastMail、ConnectionConfig関数をインストール
  2. ConnectionConfigで、メールサーバーとの接続を書く
    1. ここで詰まった。どうやら参考記事と自分が使っていたfastapi_mailのバージョンが違っていて、最新は書き方が変わったらしい。
    2.  MAIL_STARTTLS=True
        MAIL_SSL_TLS=False
  3. FastMailのインスタンスを生成 
    1. fm = FastMail(conf)
    2. ConnectionConfigをFastMailの引数として渡して、SMTP設定を引き継がせる。これにより、FastMailオブジェクトを使い、メールが送信できるようになる。FastMailオブジェクトがないと、メールの送信ができない。
  4. pydanticのEmailSchemaクラスを用いて、メール送信時の各フィールドのバリデーションを行う
    1.  class EmailSchema(BaseModel):
       name:str
       email:str
         contents: str
       tel: str
    2. これがないと、POSTで受け取った時に型が不一致になってエラーの原因になるので、優秀なクラスっぽい。pydanticすげえ。。。
  5. 情報がpostされた時に行う処理をルーティング含め書いていく
    1. MessageSchemaで、受信時のメッセージを作成していく
    2. returnに、ユーザー側に表示される内容を作っていく。これthanks.htmlとかでもええかも

コードを書き終えて、フォームからPOSTすると、下記のエラーになった。

{"detail":[{"loc":["body"],"msg":"value is not a valid dict","type":"type_error.dict"}]}

エラーが意味するのは、フォームからPOSTされた値のバリデーションが辞書型ではなく、正しくないですよ。とのこと。

 

FastAPIはデフォルトだと、JSON形式のデータを受け取ることを想定している。JSON形式のデータというのは、「KeyとValueのペアである辞書型」なのだ。

今回の場合、フォームから送信されたデータをPydanticモデル(EmailSchema)に従って

バリデーションし、データの形式を確認する。

 

しかし、HTMLフォームからデータを送信する場合、

multipart/form-dataエンコーディングが使用されるらしい。そしてmultipart/form-dataエンコーディングは、フォームのフィールドを個別のパートとして送信するそうな。

 

そのため、FASTAPIがEmailSchemaを通して、自動でバリデーションできなくなるよう。

 

ここでコードを下記のように変更した。

旧コード:

async def submit_form(email: EmailSchema):

email:EmailSchemaというのは、関数submit_formに引数emailを渡している。そして型はEmailSchemaだよということ。受け取ったデータを、EmailSchemaを通して、バリデーションするのだ。

 

新コード:

async def submit_form(name: str = Form(...), tel: str = Form(...),
email: str = Form(...), contents: str = Form(...)):