Python,Flask,Twilio SendGridを使ってメールを受信する方法
この記事は Receiving Emails with Python, Flask and Twilio SendGrid の抄訳です。
PythonのWebアプリケーション、特にFlaskを使ってメールを処理する方法をWebで検索すると、送信についての情報はたくさん見つかりますが、受信についてはあまり出てきません。
その理由は、メールを受信するアプリケーションを自分でイチから作るのはかなり難しいからです。しかし、Twilio SendGridではWebhookを利用して、メール受信を簡単に実現できるInbound Parse機能を提供しています。
このチュートリアルでは、Twilio SendGridを使ってFlaskアプリケーションで独自ドメイン宛のメールを受信する方法を紹介します。
必須条件
このチュートリアルを実施する上での必須条件は以下の通りです:
- Python 3 — ご利用のOSにPython3がプリインストールされていなければ、python.orgからインストーラをダウンロードしてください。
- Twilio SendGridのアカウント — まだアカウントをお持ちでない場合は、こちらからお申込みください。
- メールを受信するための独自ドメイン — このチュートリアルではyourdomainhere.comとして説明します。実際にご利用の独自ドメインに読み替えてください。
- ngrok — この便利なツールを使うと、ローカル環境で実行しているFlaskアプリケーションを、SendGridが接続可能なパブリックURLに公開することができます。開発環境のPCはおそらくルータやファイアウォールの内側にあり、インターネットからは直接到達できないため、このツールを利用します。ngrokがインストールされていない場合は、ご利用のOSに合ったものをダウンロードしてください。
SendGridのDomain Authentication
メールが受信できる環境を作る最初の手順は、独自ドメイン宛に来たメールをTwilio SendGridで受信できるよう、Domain Autenticationを設定することです。
独自ドメイン認証の手順
まずはSendGridのダッシュボードにログインしましょう。左のナビゲーションバーの中から「Settings」を開き、Sender Authenticationを選択します。
「Domain Authentication」セクションにある「Get Started」ボタンをクリックしてください。
まず最初に、DNSプロバイダを選択します。一覧にプロバイダがない場合や、どれを選択すればいいか不明な場合は、「I’m Not Sure」を選択します。
次にLink Brandingの設定を行うかどうかを選択します。今回のチュートリアルで行うメール受信とは関係がない内容なので、「No」を選択してください。このオプションを利用したい場合、後から変更することが可能です。
選択できたら、「Next」ボタンをクリックします。
次の画面では、ドメイン名を入力します。このチュートリアルでは、yourdomainhere.comと入力していますが、実際に試す時はご自分のドメイン名を入力してください。「Advanced Settings」は変更する必要はありません。
「Next」ボタンをクリックして次に進みます。
次の画面では、ご利用のドメインに追加する必要がある3つのDNSレコードが表示されます。各DNSレコードには、type、host、valueの属性を持っています。下の図は、yourdomainhere.comで設定した場合の例です。実際には、ご利用のドメイン名が入ります。
DNSレコードをドメインに追加する
DNSレコードを追加するには、ドメインプロバイダの管理ページにアクセスする必要があります。アクセス方法は使用しているプロバイダによって異なりますので、プロバイダが提供するコントロールパネルにアクセスし、ドメインのDNS設定がどこにあるかを確認してください。
下の図はGoogle Domainsを使用し、3つのDNSレコードのうち最初のものを追加したところです。なお、@、ftp、wwwのレコードはこのチュートリアルとは関係ありません。
この手順で1つ注意点があります。Domain Authenticationの画面で提示されるDNSレコードはem3329.yourdomainhere.comのような形式でしたが、今回利用したレジストラに登録する際はem3329だけを入力しなければなりませんでした。登録の仕方はドメインプロバイダによって異なるので、ご利用のプロバイダのルールに合わせて入力するようにしてください。
3つのDNSレコードを追加すると、DNSは下図のようになりました。(赤枠で囲んでいるのが追加した3つのレコードです)
認証を行う
DNSレコードの追加が完了したら、SendGridのSender Authenticationのページに戻ります。「STATUS」が「Pending」になっているので、ドメイン名のリンクをクリックして認証を進めます。
次の画面ではドメインに追加した3つのDNSレコードが再び表示されます。ページの右上に「Verify」ボタンが表示あるので、クリックするとSendGridは正しくDNSレコードが追加されているかを確認して認証を行います。
ドメインの認証が完了すると、画面に「It worked!」と表示されます。
もし、認証に失敗した場合は、後で再度認証を実行する必要があります。DNSレコードの変更は世界中のDNSサーバに伝搬される必要があるため、反映にはしばらく時間がかかる場合があります。DNSレコードを登録した直後に認証に失敗した場合は、しばらく待ってから再度「Verify」ボタンを押してください。長い場合は、DNSの反映に48時間かかることもあります。
「It worked!」のページが表示されたら、Domain Authenticationの設定は完了です。Flaskアプリケーションでメールを受信できるようになるまであと一歩です。
Flaskのメール受信用エンドポイント
いよいよFlaskアプリケーションでメールを受信するコードを書くところまで来ました。
Pythonの仮想環境を作成する
Pythonのベストプラクティスに従って、プロジェクト用に新しいディレクトリを作成し、その中に仮想環境を作成します。そして仮想環境にFlaskフレームワークをインストールします。
UnixまたはMac OSを使用している場合は、ターミナルを開き、以下のコマンドを入力します:
$ mkdir flask-receive-emails $ cd flask-receive-emails $ python3 -m venv venv $ source venv/bin/activate (venv) $ pip install flask
Windowsをご利用の場合はコマンドプロンプトで以下のコマンドを入力します:
$ md flask-receive-emails $ cd flask-receive-emails $ python -m venv venv $ venv\Scripts\activate (venv) $ pip install flask
Flaskでメール受信のエンドポイントを作成する
これで、メールを受信するシンプルなFlaskアプリケーションを作成する準備が整いました。完成したアプリケーションのコードを以下に示します。このコードをapp.pyというファイルに記述します。
from flask import Flask, request app = Flask(__name__) @app.route('/email', methods=['POST']) def receive_email(): print('From:', request.form['from']) print('To:', request.form['to']) print('Subject:', request.form['subject']) print('Body:', request.form['text']) return ''
アプリケーションでは、/emailをWebルートと定義しています。SendGridはメールを受信するたびにこのルートを呼び出し、メールに関するすべての情報を標準的なフォームからのポストとして送信しますので、Flaskアプリケーションでは request.form のディクショナリでメールの詳細に簡単にアクセスすることができます。
以下が特に重要な変数です:
- from: 送信元メールアドレス
- to: 宛先のメールアドレス
- subject: 件名
- text テキストパートの本文
- html HTMLパートの本文
全てのパラメータを確認するためには、SendGridのドキュメントをご覧ください。
このチュートリアルでは、メールに関する情報をコンソールに表示するFlaskのアプリケーションを作成しました。実際のアプリケーションでは、受信したメールを適切に処理する必要があります。
上記のコードをapp.pyに記入で来たら、以下のコマンドでFlaskアプリケーションを起動してください:
(venv) $ flask run * Environment: production WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Debug mode: off * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
これでアプリケーションが開始し、リクエストを待っている状態になりますが、開発用の閉じた環境でウェブサーバを実行しているため、外部からはアクセスできません。また、ファイアウォールの内側にある可能性が高いです。次のセクションでは、開発用サーバをインターネットからアクセスできるようにするための方法を説明しますので、アプリケーションはそのままにしておいてください。
Inbound Parse Webhookの設定
Flaskアプリケーションが起動できたら、残すはSendGridとの接続のみです。
ngrokを起動する
ここでは ngrok を使用して、ローカルで実行している Flask アプリケーションにSendGrid がリクエストを転送できるようにするためのパブリックなURLを作成します。これは、開発中にWebhookをテストするためによく使われる手法です。
ngrokがインストールされていなければ、インストールを行ってください。Flaskアプリケーションを実行しているのとは別のターミナル画面を開き、以下のコマンドでngrokを実行します:
$ ngrok http 5000
このコマンドは、ngrok にパブリックなインターネットからローカルマシンのポート 5000 に「トンネル」を作るように指示しています。出力は以下のようになります。
ngrokの画面で、「Forwarding」で始まる行に注目してください。これは ngrok がリクエストをローカルのサービスにリダイレクトする際に使用するパブリック URL を示しています。ここでは、暗号化されている「https://」を使用しています。
SendGridでParse Webhookを設定する
SendGridのダッシュボードに戻り、「Settings」から「Inbound Parse」を選択し、「Add Host & URL」をクリックします。
次の画面では、メールを受信するサブドメインを入力します。ご利用のドメインの任意のサブドメインにすることができます。また、トップレベルドメインでメールを受信したい場合は、空のままにすることができます。ここでは分かりやすいようにサブドメインをparseとして進めます。
次に、メールを受信するドメイン名を選択します。ドロップダウンリストにDomain Authenticationで認証が完了したドメインが一覧表示されています。先述の手順でDomain Authenticationを設定したドメインが表示されているはずです。
次に、WebhookのPost先のURLを入力します。ここにはngrokが生成したURLの末尾に/emailを付けたものを入力します。今回試した際はhttps://bbf1b72b.ngrok.io/email でした。
「Add」ボタンをクリックしてWebhookを追加します。
すると以下のような画面が表示されます:
ngrok の URL は ngrok の停止と再起動のたびに変更されるため、開発中はWebhookを編集して URL を更新する必要があることに注意してください。本番環境にWebhookを展開する際には、パブリックなURLに直接ホストすることになりますので、ngrokは必要ありません。
サブドメインの登録
前の手順でメールを受信するために選択したサブドメインには、ドメインプロバイダのDNS設定でMXレコードで定義する必要があります。この値はすべてのSendGridのユーザで共通で「mx.sendgrid.net. 」となります(”net “の後にドットが必要です)。
今回Google DomainsのDNS設定では、parseのサブドメインを次のように定義しました。
使用しているドメインプロバイダによっては、このDNSレコードに完全なホスト名を入力する必要がある場合があるのでご注意ください。
前の手順でサブドメインを定義しなかった場合、ホスト名はyourdomainhere.comまたは単に「@」となります。
最後のエントリをドメインのレジストラに追加すると、再びDNSに反映されるのを待つ必要があります。
テストメールを送信する
様々な手順を踏んできましたが、これでメールを受信する環境のセットアップは完了です!
Flaskアプリケーションとngrokを起動している状態で、メールクライアントを開き、テストメールを送信してみましょう。ローカルパートには好きな文字列を指定することができます。@以降には、Parse Webhookで設定したサブドメインを含む完全なドメイン名を指定してください。
今回は以下のように指定しました
test@parse.yourdomainhere.com:
メールを送信した後、1〜2分待つと、SendGridがngrok webhookのURLを呼び出し、Flaskのエンドポイントを呼び出します。今回実装したシンプルなFlaskアプリケーションでは、受信したメールのデータをコンソールに表示します。
これで無事Flaskアプリケーションでメールが受信できるようになりました!
本番環境での注意点
開発時にデプロイしたWebhookと本番利用を目的としたWebhookの重要な違いをいくつかご紹介します。
ngrokを使わずにデプロイする
まず、先述の内容からも分かるように、ngrokは本番環境用のデプロイでは使用しません。その代わり、インターネットに直接接続されているサーバにFlaskアプリケーションをデプロイします。Flaskのドキュメントで、いくつかデプロイ方法が紹介されています。
Webhookのセキュリティ
もう一つ重要なのは、本番環境用のエンドポイントに何らかのセキュリティを適用することです。パブリックな環境に公開されているエンドポイントは、そのURLを知っている人なら誰でも呼び出すことができるので、SendGridを装った悪意のあるユーザから、偽の呼び出しを受ける危険をはらんでいます。
こういった攻撃への良い対策方法は、FlaskエンドポイントにBasic認証を実装し、エンドポイントの実行に必要なユーザ名とパスワードを定義することです。この方法をFlaskアプリケーションに取り入れたい場合、Flask-HTTPAuthエクステンションが役立ちます。
エンドポイントにBasic認証を追加した場合、SendGridに設定するURLにユーザ名とパスワードを含める必要があります。上記で使用したWebhookでBasic認証を有効にしていた場合、URLはhttps://username:password@bbf1b72b.ngrok.io/emailとなります。
まとめ
メールを受信するアプリケーションを作るために多くの手順が必要だと思われたかもしれませんが、今回ご紹介した内容が最もシンプルな方法のひとつです。
Inbound Parse Webhookを使ってどんなアプリケーションを作成したくなりましたか?この記事がお役に立てれば幸いです。