本記事では、チュートリアルとしてFlaskによるcontact-form作成から以下の学習を体験できます。
- PRGパターン(POST/REDIRECT/GET)の理解
- request, redirectモジュールの理解と使い方
- formの使い方
上記を中心にFlaskチュートリアルを進めていきます。
requestの使い方
ここでは、requestの使い方としてパラメータの取得方法を解説します。
以下は、代表的なrequestオブジェクトの属性とメソッドになります。
属性またはメソッド | 説明 |
---|---|
method | リクエストメソッド |
form | リクエストフォーム |
args | クエリパラメータ |
cookies | リクエストクッキー(Cookie) |
files | リクエストファイル |
environ | 環境変数 |
headers | リクエストヘッダー |
referrer | リクエストのリファラ(リンク元のページ) |
query_string | リクエストクエリ文字列 |
Scheme | リクエストのプロトコル(http/https) |
url | リクエストURL |
また、GETリクエストとPOSTリクエストによってデータの取得方法は異なるため注意が必要です。
パラメータの取得方法
以下は、一般的なパラメータの取得方法の種類です。
- GET/POSTリクエストパラメータ
- URI(パス)パラメータ
GET/POSTリクエストパラメータ
以下は、GETリクエストのパラメータの取得方法になります。
コード | 説明 |
---|---|
request.args[key] | GETパラメータ(Keyがなければエラー) |
request.args.get(key) | GETパラメータ(KeyがなければNone) |
request.args.get(key, “…”) | GETパラメータがない場合のデフォルト値を指定 |
request.args.get(key, type=int) | GETパラメータをint型で受け取る |
以下は、POSTリクエストのパラメータの取得方法になります。
コード | 説明 |
---|---|
request.form[key] | POSTパラメータ(Keyがなければエラー) |
request.form.get(key) | POSTパラメータ(KeyがなければNone) |
request.form.get(key, “…”) | POSTパラメータがない場合のデフォルト値を指定 |
request.form.get(key, type=int) | POSTパラメータをint型で受け取る |
URI(パス)パラメータ
以下は、URI(パス)パラメータを使用する際のサンプルコードになります。
@app.route("/user/<user_id>")
def user(user_id):
print(user_id)
URIパラメータの場合はデコレータ関数である@app.route()にてパスの一部として扱います。
また、関数であるuser()の引数に指定することで値を受け取れます。
redirectの使い方
ここでは、redirectの使い方を解説します。
- redirectによるURLの指定
- redirectによる関数名の指定
それぞれのパターンを確認しておきましょう。
redirectによるURLの指定
redirectを利用することで、指定したURLに遷移できます。
from flask import redirect
@app.route("/")
def main():
return redirect("https://jobcode.jp/")
redirectによる関数名の指定
redirect()にurl_forを利用することで関数名の指定もできます。
from flask import redirect, url_for
@app.route("/")
def main():
...省略...
@app.route("/sub_main")
def sub_main():
return redirect(url_for("main"))
問い合わせフォームの仕様
本チュートリアルは、以下のシンプルなcontact-formを作成します。
- 問い合わせフォーム画面
- 問い合わせ完了画面
上記の2画面にて構成します。
ここでは、特にデータベースを利用せず問い合わせフォームから問い合わせすると、入力したメールアドレスに内容を送信し問い合わせ完了になります。
PRGパターンとは
PRGパターンはPOST/REDIRECT/GETの略です。
フォームデータを送信(POST)したら再読み込み(REDIRECT)し、取得(GET)したページを表示することを指します。
PRGパターンを使わない場合、フォームデータをPOSTしたあと再ロードすると元のコンテンツが再送され、フォームデータが二重で送られる可能性があります。
上記の問題を回避するために多くのケースでPRGパターンを利用します。
本チュートリアルでは、以下の工程を考えます。
- contact-form画面を表示する(GET)
- 問い合わせ内容をメールで送信する(POST)
- 問い合わせ完了画面へリダイレクトする(REDIRECT)
- 問い合わせ完了画面を表示する(GET)
また、ルート情報は以下の表になります。
Endpoint | Methods | Rule |
---|---|---|
contact | GET | /contact |
contact_complete | GET, POST | /contact/complete |
request(リクエスト)とredirect(リダイレクト)
リクエスト情報を取得するには、flaskモジュールからrequestをimportします。
また、別のエンドポイントをリダイレクトするにはredirect関数を利用します。
# 必要なモジュールをインポート
from flask import Flask, render_template, url_for, request, redirect
contact-formのエンドポイントを作成する
任意で作成したディレクトリにてapp.pyを作成し、以下のエンドポイントを追加します。
- contact-form画面を表示するエンドポイント
- リダイレクト後の問い合わせ完了画面を表示するエンドポイント
メール送信処理はコメントにて一旦保留にして後述します。
# Flaskのインポート
from flask import Flask, render_template, url_for, request, redirect
# Flaskクラスをインスタンス化
app = Flask(__name__)
# URLと実行する関数をマッピング
@app.route("/contact", methods=["GET"])
def contact():
return render_template("contact.html")
@app.route("/contact/complete", methods=["GET", "POST"])
def contact_complete():
if request.method == "POST":
# メール送信は一旦保留(後述)
# contact_completeエンドポイントへリダイレクト
return redirect(url_for("contact_complete"))
return render_template("contact_complete.html")
- contact-form画面を返すcontactエンドポイント作成
- contact-form処理/完了画面を返すcontact_completeエンドポイント作成
@app.route()デコレータの第二引数にmethods=[“GET”, “POST”]を指定し、GETとPOSTメソッドを許可 - request.method属性を利用してリクエストされたメソッドをチェック
- GETの場合は問い合わせ完了画面を返す
POSTの場合はcontact_completeエンドポイントへリダイレクト
contact-formのテンプレートを作成する
任意のディレクトリ配下にtemplatesディレクトリを作成し、問い合わせフォーム画面であるcontact.htmlと問い合わせ完了画面であるcontact_complete.htmlを作成します。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>CONTACT</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css' )}}" />
</head>
<body>
<div class="contact-bg">
<div class="contact-area inner">
<p class="contact-message">
お問い合わせ、ご要望等がございましたら、お気軽にお問い合わせください。<br>
下記のプライバシーポリシーをご確認の上、送信してください。<br>
<span class="message-notice"><span class="essential">必須</span>は必須項目です。</span>
</p>
<p class="text notosan">
<a href="#">送信にあたっては、こちらのプライバシーポリシーをご覧ください。</a>
</p>
<div class="contact-inner">
<form action="{{ url_for('contact_complete' )}}" method="POST" novalidate="novalidate">
<table class="contact-table">
<tr class="table-list">
<th>
<label for="name">お名前<span class="essential">必須</span></label>
</th>
<td>
<input type="text" name="username" value="{{ username }}" placeholder="お名前をご入力ください" class="input-area" autocomplete="name">
</td>
</tr>
<tr class="table-list">
<th>
<label for="mail">メールアドレス<span class="essential">必須</span></label>
</th>
<td>
<input type="text" name="mail" value="{{ email }}" placeholder="メールアドレスをご入力ください" class="input-area" autocomplete="email">
</td>
</tr>
<tr class="table-list">
<th>
<label for="description">お問い合わせ内容<span class="essential">必須</span></label>
</th>
<td>
<textarea id="description" name="description">{{ description }}</textarea>
</td>
</tr>
</table>
</form>
<input type="submit" value="送信する" class="submit-button">
</div>
</div>
</div>
</body>
</html>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>CONTACT-COMPLETE</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css' )}}" />
</head>
<body>
<div class="contact-bg">
<div><h3 class="contact-h3">CONTACT</h3></div>
<div><h1 class="contact-h1">お問い合わせ完了</h1></div>
<div class="contact-area inner">
<p class="contact-message">
お問い合わせありがとうございます。<br>
担当者よりご連絡させていただきます。<br>
</p>
<p class="text notosan">
<a href="#">TOPページに戻る</a>
</p>
</div>
</div>
</body>
</html>
任意のディレクトリ配下に、static/style.cssを作成し、以下のスタイルコードを追加します。
.contact-bg {
background: #e4eeef;
padding: 100px 0;
margin: 0 auto 0;
}
.contact-h1 {
text-align: center;
}
.contact-h3 {
text-align: center;
}
.contact-message {
text-align: center;
font-size: 14px;
line-height: 2;
margin-bottom: 50px;
}
.message-notice {
color: #c10811;
font-size: 14px;
}
.essential {
background: #c10811;
color: #fafafa;
font-size: 12px;
padding: 0 10px;
font-weight: normal;
margin-left: 10px;
}
.contact-area {
background: #fafafa;
padding: 90px;
margin: 100px auto;
width: 1000px;
}
.contact-table {
width: 100%;
}
.table-list {
display: flex;
justify-content: space-between;
font-family: 'Noto Sans JP', sans-serif;
letter-spacing: 0.05em;
width: 100%;
margin-bottom: 40px;
}
.table-list th {
font-size: 13px;
font-weight: bold;
width: 250px;
text-align: left;
}
.table-list-address {
flex-wrap: wrap;
}
.table-list-address .input-area {
margin-bottom: 10px;
}
.input-area {
font-family: 'Noto Sans JP', sans-serif;
letter-spacing: 0.05em;
padding: 0 10px;
border: none;
width: 550px;
height: 40px;
box-sizing: border-box;
border: 1px solid #c4c4c4;
}
.table-list td {
font-size: 13px;
width: calc(100% - 250px);
}
input::placeholder {
color: #bfbfbf;
font-size: 12px;
font-weight: bold;
}
textarea {
border: none;
width: 550px;
height: 200px;
padding: 0;
border: 1px solid #c4c4c4;
resize: vertical; /* 横方向のみサイズを固定する */
}
textarea::placeholder {
color: #bfbfbf;
font-size: 12px;
}
input[type="text"] {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
.contact-area .text {
font-size: 13px;
text-align: center;
margin-bottom: 100px;
}
.contact-area .text a {
color: #000;
border-bottom: 1px solid #000;
transition: all .3s;
text-decoration: none;
}
.contact-area .text a:hover {
border-bottom: 1px solid #777;
padding-bottom: 5px;
color: #777;
}
.submit-button {
box-sizing: border-box;
position: relative;
display: block;
margin: 30px auto 0;
background-color: #e4eeef;
cursor: pointer;
border: 1px solid #e4eeef;
color: #000;
text-align: center;
text-decoration: none;
line-height: 1.5;
outline: none;
-webkit-transition: all .3s;
transition: all .5s;
padding: 20px 100px;
}
.submit-button:hover {
background: #cae1e3;
color: #000;
border: 1px solid #cae1e3;
}
@media(max-width:1200px) {
.contact-area {
width: 80%;
padding: 60px;
}
}
@media(max-width:1024px) {
.contact-area {
padding: 50px 15px;
}
.table-list th {
width: 180px;
}
.table-list td {
width: 100%;
}
.input-area {
width: 500px;
height: 40px;
}
textarea {
width: 500px;
height: 200px;
}
.contact-message {
margin-bottom: 30px;
}
.contact-area .text {
margin-bottom: 30px;
}
}
@media(max-width:834px) {
.contact-bg {
margin: 50px auto 0;
padding: 50px 0;
}
.contact-area {
margin: 50px auto;
padding: 50px 20px;
}
.check-box label {
width: 100%;
}
.input-area {
width: 100%;
height: 30px;
}
textarea {
width: 100%;
height: 200px;
}
.table-list {
flex-wrap: wrap;
margin-bottom: 20px;
}
.table-list th {
font-size: 12px;
width: 200px;
margin-bottom: 10px;
}
.table-list td {
font-size: 12px;
}
.table-list td {
width: 100%;
}
.contact-message {
font-size: 13px;
}
.contact-area .text {
font-size: 13px;
}
}
@media (max-width:640px) {
.contact-message {
text-align: left;
}
.contact-area .text {
text-align: left;
}
}
@media(max-width:320px) {
.input-area {
width: 100%;
}
textarea {
width: 100%;
}
}
上記のファイル群を追加し、任意のディレクトリにてflask runコマンドを実行すると確認できます。
POSTされたformの値を取得する
POSTされたformの値を取得するには、requestのform属性を利用します。
app.pyのcotanct_completeエンドポイントを修正します。
# Flaskのインポート
from flask import Flask, render_template, url_for, request, redirect
# Flaskクラスをインスタンス化
app = Flask(__name__)
# URLと実行する関数をマッピング
@app.route("/contact", methods=["GET"])
def contact():
return render_template("contact.html")
@app.route("/contact/complete", methods=["GET", "POST"])
def contact_complete():
if request.method == "POST":
# form属性から値を取得する
username = request.form["username"]
email = request.form["email"]
description = request.form["description"]
# contact_completeエンドポイントへリダイレクト
return redirect(url_for("contact_complete"))
return render_template("contact_complete.html")
Flashメッセージ(email-validator)
Flashメッセージは、処理後にメッセージを表示する機能です。
完了時やエラー時など、一時的なメッセージを表示したい場合に利用します。
Flashメッセージを利用するために以下の処理を追加します。
- SECRET_KEYを設定する
- バリデーションを追加する
SECRET_KEYを設定する
contact-form画面にバリデーション(入力チェック処理)を追加します。
入力チェック時にエラーが発生した場合、Flashメッセージを表示します。
Flashメッセージはflash関数にて設定し、テンプレートにてget_flashed_messages関数で取得し表示します。
セッションが必要になるため、コンフィグのSECRET_KEYを設定します。
ここでは、コンフィグファイルではなく、app.pyに書き込んでいます。
以下のコードでコンフィグを追加・設定することができます。
app.config["config_key"] = config_value
セッション(Session)を利用するためには、セッション情報をセキュリティで守る秘密鍵(SECRET_KEY)を設定します。
秘密鍵はランダムな値にする必要があります。
ここでは、以下のサイトを利用してランダムな秘密鍵を生成しました。
# ...省略...
app = Flask(__name__)
# SECRET_KEYを追加する
app.config["SECRET_KEY"] = "生成したパスワード"
バリデーションを追加する
次に、バリデーション(入力チェック処理)を追加します。
また、メールアドレスが正しいかチェックするemail-validatorパッケージをインストールします。
pip install email-validator
# Flashの追加
from flask import Flask, render_template, url_for, request, redirect, flash
# email_validatorをインポート
from email_validator import validate_email, EmailNotValidError
# Flaskクラスをインスタンス化
app = Flask(__name__)
# SECRET_KEYを追加する
app.config["SECRET_KEY"] = "生成したパスワード"
# URLと実行する関数をマッピング
@app.route("/contact", methods=["GET"])
def contact():
return render_template("contact.html")
@app.route("/contact/complete", methods=["GET", "POST"])
def contact_complete():
if request.method == "POST":
# form属性から値を取得する
username = request.form["username"]
email = request.form["email"]
description = request.form["description"]
# バリデーションチェック追加
is_valid = True
if not username:
flash("ユーザー名は必須です")
is_valid = False
if not email:
flash("メールアドレスは必須です")
is_valid = False
try:
validate_email(email)
except EmailNotValidError:
flash("メールアドレス形式で入力してください")
is_valid = False
if not description:
flash("問い合わせ内容は必須です")
is_valid = False
if not is_valid:
return redirect(url_for("contact"))
# contact_completeエンドポイントへリダイレクト
return redirect(url_for("contact_complete"))
return render_template("contact_complete.html")
- Flaskにてflashを追加インポート
- メールアドレス形式チェック用でvalidate_emailとEmailNotValidErrorをインポート
- validate_email関数にてチェックし、形式が不正の場合に例外処理としてtry-except文で囲む
- is_validがFalseの場合はリダイレクト
flashに設定したエラーメッセージをcontact-form画面で表示するために、HTMLファイルでget_flashed_messsages関数を利用します。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>CONTACT</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css' )}}" />
</head>
<body>
<div class="contact-bg">
<div class="contact-area inner">
<p class="contact-message">
お問い合わせ、ご要望等がございましたら、お気軽にお問い合わせください。<br>
下記のプライバシーポリシーをご確認の上、送信してください。<br>
<span class="message-notice"><span class="essential">必須</span>は必須項目です。</span>
</p>
<p class="text notosan">
<a href="#">送信にあたっては、こちらのプライバシーポリシーをご覧ください。</a>
</p>
<div class="contact-inner">
<form action="{{ url_for('contact_complete' )}}" method="POST" novalidate="novalidate">
<table class="contact-table">
<tr class="table-list">
<th>
<label for="name">お名前<span class="essential">必須</span></label>
</th>
<td>
<input type="text" name="username" value="{{ username }}" placeholder="お名前をご入力ください" class="input-area" autocomplete="name">
</td>
</tr>
<tr class="table-list">
<th>
<label for="mail">メールアドレス<span class="essential">必須</span></label>
</th>
<td>
<input type="text" name="email" value="{{ email }}" placeholder="メールアドレスをご入力ください" class="input-area" autocomplete="email">
</td>
</tr>
<tr class="table-list">
<th>
<label for="description">お問い合わせ内容<span class="essential">必須</span></label>
</th>
<td>
<textarea id="description" name="description">{{ description }}</textarea>
</td>
</tr>
</table>
{% with messages = get_flashed_messages() %}
{% if messages %}
<ul>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
<input type="submit" value="送信する" class="submit-button">
</form>
</div>
</div>
</div>
</body>
</html>
問い合わせ内容のテキストエリアと送信ボタンの間にFlashメッセージが出現します。(メール送信時)
ロギング(logging)を利用する
開発時や運用時に予期しないエラーが発生する場合など、アプリで何が発生しているか確認したいケースがあります。
上記の場合にロギング(loggingモジュール)が利用できます。
ロガー(logger)にはログレベルが存在し、指定したログレベルよりもレベルが高いログだけ出力できます。
レベル | 概要 | 説明 |
---|---|---|
CRITICAL | 致命的なエラー | プログラム異常終了を伴うエラー情報 |
ERROR | エラー | 予期しない実行時エラー情報 |
WARNING | 警告 | エラーに近い減少などの準正常系情報 |
INFO | 情報 | 正常動作の確認に必要な情報 |
DEBUG | デバッグ情報 | 開発時に必要な情報 |
例えば、開発時であればDEBUG、本番環境であればERRORなど、環境によってログレベルを切り替えるイメージです。
ログレベルは、app.pyにapp.logger.setLevel関数を利用し指定します。
# Flashの追加
from flask import Flask, render_template, url_for, request, redirect, flash
# email_validatorをインポート
from email_validator import validate_email, EmailNotValidError
# loggingをインポート
import logging
# Flaskクラスをインスタンス化
app = Flask(__name__)
# SECRET_KEYを追加する
app.config["SECRET_KEY"] = "生成したパスワード"
# ログレベルの設定
app.logger.setLevel(logging.DEBUG)
# URLと実行する関数をマッピング
@app.route("/contact", methods=["GET"])
def contact():
return render_template("contact.html")
@app.route("/contact/complete", methods=["GET", "POST"])
def contact_complete():
if request.method == "POST":
# form属性から値を取得する
username = request.form["username"]
email = request.form["email"]
description = request.form["description"]
# バリデーションチェック追加
is_valid = True
if not username:
flash("ユーザー名は必須です")
is_valid = False
if not email:
flash("メールアドレスは必須です")
is_valid = False
try:
validate_email(email)
except EmailNotValidError:
flash("メールアドレス形式で入力してください")
is_valid = False
if not description:
flash("問い合わせ内容は必須です")
is_valid = False
if not is_valid:
return redirect(url_for("contact"))
# contact_completeエンドポイントへリダイレクト
return redirect(url_for("contact_complete"))
return render_template("contact_complete.html")
ログを出力するには以下のように指定します。
app.logger.ciritical("fatal error")
app.logger.error("error")
app.logger.warning("warning")
app.logger.info("info")
app.logger.debug("debug")
flask-debugtoolbarのインストール
Flaskで開発する際、デバッグ用モジュールとしてflask-debugtoolbarが利用できます。
flask-debugtoolbarは以下のコマンドでインストールします。
pip install flask-debugtoolbar
# Flashの追加
from flask import Flask, render_template, url_for, request, redirect, flash
# email_validatorをインポート
from email_validator import validate_email, EmailNotValidError
# flask-debugtoolbarをインポート
from flask_debugtoolbar import DebugToolbarExtension
# loggingをインポート
import logging
# Flaskクラスをインスタンス化
app = Flask(__name__)
# SECRET_KEYを追加する
app.config["SECRET_KEY"] = "生成したパスワード"
# ログレベルの設定
app.logger.setLevel(logging.DEBUG)
# リダイレクトを中断しないように設定
app.config["DEBUG_TB_INTERCEPT_REDIRECTS"] = False
# DebugToolbarExtensionにアプリケーションをセット
toolbar = DebugToolbarExtension(app)
# URLと実行する関数をマッピング
@app.route("/contact", methods=["GET"])
def contact():
return render_template("contact.html")
@app.route("/contact/complete", methods=["GET", "POST"])
def contact_complete():
if request.method == "POST":
# form属性から値を取得する
username = request.form["username"]
email = request.form["email"]
description = request.form["description"]
# バリデーションチェック追加
is_valid = True
if not username:
flash("ユーザー名は必須です")
is_valid = False
if not email:
flash("メールアドレスは必須です")
is_valid = False
try:
validate_email(email)
except EmailNotValidError:
flash("メールアドレス形式で入力してください")
is_valid = False
if not description:
flash("問い合わせ内容は必須です")
is_valid = False
if not is_valid:
return redirect(url_for("contact"))
# contact_completeエンドポイントへリダイレクト
return redirect(url_for("contact_complete"))
return render_template("contact_complete.html")
ブラウザでURLにアクセスすると、ブラウザの右側にデバッグツールバーが表示されます。
メール(flask-mail)を送信する
contact-form画面から問い合わせした際に、メールを送信する機能を実装します。
FlaskのFlask-mailモジュールをインストールします。
pip install flask-mail
flask-mailをインストールしたらコンフィグを設定します。
設定 | デフォルト値 | 説明 |
---|---|---|
MAIL_SERVER | localhost | メールサーバーのホスト名 |
MAIL_POST | 25 | メールサーバーのポート番号 |
MAIL_USE_TLS | False | TLSを有効にするか |
MAIL_USE_SSL | False | SSLを有効にするか |
MAIL_DEBUG | app.debug | デバッグモード |
MAIL_USERNAME | None | 送信元メールアドレス |
MAIL_PASSWORD | None | 送信元メールアドレスのパスワード |
MAIL_DEFAULT_SENDER | None | メールの送信者名およびメールアドレス |
Gmailにてアプリからメールの送信準備
Gmailを利用してアプリからメールを送信するには、以下の2段階認証プロセスページで設定します。
以下のアプリパスワードページでアプリ用のパスワードを取得する必要があります。
生成できたパスワードは、MAIL_PASSWORDに利用します。
メール送信機能を実装する
ここからメール送信機能を実装するために、以下の工程を踏んでいきます。
- flask-mailを利用する
- コンフィグの設定値を追加する
- メールを送信する
- メールテンプレートの作成
flask-mailを利用する
ここからメール送信の機能を実装します。
# Flashの追加
from flask import Flask, render_template, url_for, request, redirect, flash
# email_validatorをインポート
from email_validator import validate_email, EmailNotValidError
# flask-debugtoolbarをインポート
from flask_debugtoolbar import DebugToolbarExtension
# flask-mailをインポート
from flask_mail import Mail
# loggingをインポート
import logging
# osをインポート
import os
# Flaskクラスをインスタンス化
app = Flask(__name__)
# SECRET_KEYを追加する
app.config["SECRET_KEY"] = "生成したパスワード"
# ログレベルの設定
app.logger.setLevel(logging.DEBUG)
# リダイレクトを中断しないように設定
app.config["DEBUG_TB_INTERCEPT_REDIRECTS"] = False
# DebugToolbarExtensionにアプリケーションをセット
toolbar = DebugToolbarExtension(app)
# Mailクラスのコンフィグ設定
app.config["MAIL_SERVER"] = os.environ.get("MAIL_SERVER")
app.config["MAIL_PORT"] = os.environ.get("MAIL_PORT")
app.config["MAIL_USE_TLS"] = os.environ.get("MAIL_USE_TLS")
app.config["MAIL_USERNAME"] = os.environ.get("MAIL_USERNAME")
app.config["MAIL_PASSWORD"] = os.environ.get("MAIL_PASSWORD")
app.config["MAIL_DEFAULT_SENDER"] = os.environ.get("MAIL_DEFAULT_SENDER")
# flask-mailを登録する
mail = Mail(app)
# URLと実行する関数をマッピング
@app.route("/contact", methods=["GET"])
def contact():
return render_template("contact.html")
@app.route("/contact/complete", methods=["GET", "POST"])
def contact_complete():
if request.method == "POST":
# form属性から値を取得する
username = request.form["username"]
email = request.form["email"]
description = request.form["description"]
# バリデーションチェック追加
is_valid = True
if not username:
flash("ユーザー名は必須です")
is_valid = False
if not email:
flash("メールアドレスは必須です")
is_valid = False
try:
validate_email(email)
except EmailNotValidError:
flash("メールアドレス形式で入力してください")
is_valid = False
if not description:
flash("問い合わせ内容は必須です")
is_valid = False
if not is_valid:
return redirect(url_for("contact"))
# contact_completeエンドポイントへリダイレクト
return redirect(url_for("contact_complete"))
return render_template("contact_complete.html")
- 環境変数を取得するためにosをimport
- Mailクラスをimport
- Mailクラスのコンフィグを環境変数から取得
- flask-mailをアプリに登録
コンフィグの設定値を追加する
次に、.envファイルにflask-mailコンフィグの設定値を追加します。
FLASK_APP = apps.minimalapp.app.py
FLASK_DEBUG = 1
# flask-mailのコンフィグ設定
MAIL_SERVER = smtp.gmail.com
MAIL_PORT = 587
MAIL_USE_TLS = True
MAIL_USERNAME = [Gmailメールアドレス]
MAIL_PASSWORD = [2段階認証で発行したパスワード]
MAIL_DEFAULT_SENDER = アプリ名 <Gmailメールアドレス>
メールを送信する
次に、cotact_completeエンドポイントにメール送信する処理を追加します。
# Flashの追加
from flask import Flask, render_template, url_for, request, redirect, flash
# email_validatorをインポート
from email_validator import validate_email, EmailNotValidError
# flask-debugtoolbarをインポート
from flask_debugtoolbar import DebugToolbarExtension
# flask-mailをインポート(Messageを追加)
from flask_mail import Mail, Message
# loggingをインポート
import logging
# osをインポート
import os
# Flaskクラスをインスタンス化
app = Flask(__name__)
# SECRET_KEYを追加する
app.config["SECRET_KEY"] = "&ppphc6dM-Hp"
# ログレベルの設定
app.logger.setLevel(logging.DEBUG)
# リダイレクトを中断しないように設定
app.config["DEBUG_TB_INTERCEPT_REDIRECTS"] = False
# DebugToolbarExtensionにアプリケーションをセット
toolbar = DebugToolbarExtension(app)
# Mailクラスのコンフィグ設定
app.config["MAIL_SERVER"] = os.environ.get("MAIL_SERVER")
app.config["MAIL_PORT"] = os.environ.get("MAIL_PORT")
app.config["MAIL_USE_TLS"] = os.environ.get("MAIL_USE_TLS")
app.config["MAIL_USERNAME"] = os.environ.get("MAIL_USERNAME")
app.config["MAIL_PASSWORD"] = os.environ.get("MAIL_PASSWORD")
app.config["MAIL_DEFAULT_SENDER"] = os.environ.get("MAIL_DEFAULT_SENDER")
# flask-mailを登録する
mail = Mail(app)
# URLと実行する関数をマッピング
@app.route("/contact", methods=["GET"])
def contact():
return render_template("contact.html")
@app.route("/contact/complete", methods=["GET", "POST"])
def contact_complete():
if request.method == "POST":
# form属性から値を取得する
username = request.form["username"]
email = request.form["email"]
description = request.form["description"]
# バリデーションチェック追加
is_valid = True
if not username:
flash("ユーザー名は必須です")
is_valid = False
if not email:
flash("メールアドレスは必須です")
is_valid = False
try:
validate_email(email)
except EmailNotValidError:
flash("メールアドレス形式で入力してください")
is_valid = False
if not description:
flash("問い合わせ内容は必須です")
is_valid = False
if not is_valid:
return redirect(url_for("contact"))
# メール送信
send_email(
email,
"お問い合わせありがとうございました。",
"contact_mail",
username = username,
description = description,
)
# contact_completeエンドポイントへリダイレクト
return redirect(url_for("contact_complete"))
return render_template("contact_complete.html")
# メール送信関数
def send_email(to, subject, template, **kwargs):
msg = Message(subject, recipients=[to])
msg.body = render_template(template + ".txt", **kwargs)
msg.html = render_template(template + ".html", **kwargs)
mail.send(msg)
- flask-mailにてMessageを追加インポート
- メール送信の処理としてメール送信関数を呼び出す
- メール送信関数を追加
メールテンプレートの作成
次に、メールテンプレートを作成します。
templatesディレクトリにテキスト版のcontact_mail.txtとHTML版のcontact_mail.htmlに作成します。
{{ username }} 様
お問い合わせありがとうございます。
お問い合わせ内容はこちらになります。
▼お問い合わせ内容
{{ description }}
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>CONTACT-COMPLETE</title>
</head>
<body>
<p>{{ username }} 様</p>
<p>お問い合わせありがとうございます。</p>
<p>お問い合わせ内容はこちらになります。</p>
<p>お問い合わせ内容</p>
<p>{{ description }}</p>
</body>
</html>
contact-formの動作確認
最後に、cotact-formが問題なく動作するか確認します。
任意のディレクトリにて、flask runコマンドを実行し/contactへアクセスしてください。
実際にメール送信を実行し送信できていれば完了です。
コメント