Webサイトの登録フォームを作成する場合でも、無効なメールアドレスをメーリングリストから削除する場合でも、メールバリデーションの処理を行わずにはいられなくなります。
メールアドレスが本物かどうか、必要な条件を満たしているか、メールを受信できるかを検証する必要があります。
それを効率よく、安全に行わなければなりません。
そこで登場するのが email-validator
です。
これは、メールアドレスの検証を行うための、使いやすく、かつ堅牢な Python ライブラリです。
このガイドでは、このライブラリの基本を説明し、いつ、なぜ使うことができるのか、また、いつ使ってはいけないのかを発見していきます。
また、email-validator
の使い方を理解するために、実用的な例で説明します。
email-validatorとは何ですか?
前にも述べたように、email-validator
はメールアドレスの検証を行う堅牢な Python ライブラリです。
構文検証と配送可能性検証の2種類の検証を行います。
メールアドレスが有効とみなされるには、必要な形式を満たしていると同時に解決可能なドメイン名を持っている必要があるので、これは重要なことです。
構文検証は、電子メールアドレスの文字列表現が example@stackabuse.com
のような形式であることを確認します。
配送性検証は、構文的に正しいメールアドレスが、解決可能なドメイン名(@
記号の後の文字列 – stackabuse.com
)を持つことを保証します。
簡単に言うと、検証されたメールアドレスがメールを送受信できることを保証するものです。
さらに、 email-validator
には小さなボーナスがあります。
メールアドレスが有効な場合、 email-validator
はその正規化されたフォームを返すので、適切な方法でデータベースに保存することができます。
一方、メールアドレスが無効な場合は、 email-validator
が、渡されたメールアドレスがなぜ無効なのかを理解するために、明確で人間が読みやすいエラーメッセージを与えてくれます。
最も単純な形として、メールアドレスの正規化とは、メールアドレスのドメイン(@
記号の後の列)を小文字にすることを意味します(大文字と小文字は区別されないからです)。
より複雑な正規化では、ドメイン部分にUnicode文字が含まれる場合、正規化にはUnicode文字とASCII文字の間の様々な変換が含まれます。
問題は、異なる Unicode 文字列がエンドユーザーにとって同じように見え、同じように意味するという事実にあります。
したがって、正規化は、これらの文字列が実際には同じドメインを表すため、同じ方法で記録されることを保証する必要があります。
このライブラリは example@domainname.com
の形式を満たさない電子メールアドレスで動作するように設計されていないことに言及することは重要です。
例えば、メールメッセージの To:
行を正しく検証することはできません (例えば、To: Example Name <example@domainname.com
など)。
Email-validator と RegEx によるメール検証の比較
私たちは通常、メールアドレスの正しい形式を検証するためにある種の正規表現 (RegEx) を使用します。
これは、あるメールアドレスが必要な形式を満たしていることを確認するだけなら、素晴らしい選択です。
これはよく知られた手法であり、記述や保守が簡単で、実行にそれほど多くの計算能力を消費しません。
RegExを使ったメールアドレスの検証についてもっと知りたい方は、Pythonをご覧ください。
正規表現を使ったメールアドレスの検証を読んでみたい方は、Python: Validate Email Address with Regular Expressions!
をご覧ください。
一方、メールアドレスの検証は、時にはもっと複雑になることがあります。
メールアドレスを含む文字列は、メールアドレスの指定された形式を満たしていても、ドメインが解決されていないため、適切なメールアドレスとはみなされないことがあります。
例えば、example@ssstackabuse.com
はメールアドレスの指定された形式を満たしていますが、ドメイン名(sstackabuse.com
)が存在しないため有効ではなく、したがって、例のメールアドレスはメールメッセージを送受信することができないからです。
一方、example@stackabuse.com
は、有効な電子メールアドレスの両方の要件を満たしています。
望ましい形式を満たしており、ドメイン名も解決されます。
したがって、これは有効な電子メールアドレスとみなすことができます。
この場合、email-validator
は優れた解決策を提供します。
構文と配送の両方の検証を1つの簡単な関数呼び出しで行うので、メールアドレスが実際にメールを送受信できることを確認するのに悩む必要はありません。
この2つの検証を正規表現だけでコーディングするのは不可能です。
注:メールを送信してその結果を見なければ、メールが届くかどうかを保証することは事実上不可能です。
しかし、定型的な可能性としてメールを受信できるかを確認することはできます。
この2つの点から、正規表現に対して email-validator
を強く推すことができる。
その方が使いやすく、なおかつより多くのタスクを効率的に実行することができます。
email-validatorのインストール方法は?
email-validatorライブラリは PyPI で公開されているので、
pipまたは
pip3` を使って簡単にインストールすることができます。
$ pip install email-validator
$ pip3 install email-validator
これで email-validator
をPythonスクリプトで使用する準備ができました。
email-validatorでメールアドレスを検証する?
email-validatorライブラリの核となるのは
validate_email()メソッドです。
これはメールアドレスの文字列表現を引数として受け取り、そのアドレスの検証を行います。
渡されたメールアドレスが有効な場合、validate_email()メソッドは渡されたメールアドレスの正規化されたフォームを含むオブジェクトを返します。
しかし、無効なメールアドレスの場合は、EmailNotValidError` を発生させて明確かつ人間が読めるエラーメッセージで、なぜそのメールアドレスが無効であるのかを理解できるように説明します。
EmailNotValidError` は実際には単なる抽象クラスで、バリデーションプロセスでエラーが発生したことを検出するために使用されます。
したがって、実際のエラーを表現して記述するために使用するわけではありません。
そのため、 EmailNotValidError
クラスには、実際に発生したエラーを記述するためのサブクラスが 2 つ用意されています。
最初のクラスは EmailSynaxError
で、シンタックスバリデーションに失敗したときに発生する。
2つ目は EmailUndeliverableError
で、これは配信可能性の検証に失敗したときに発生します。
つまり、渡されたメールアドレスのドメイン名が存在しないことを意味します。
さて、いよいよ validate_email()
メソッドの使い方を見ていきましょう。
もちろん、最初のステップはこのメソッドをスクリプトにインポートすることで、すぐに使うことができます。
from email_validator import validate_email
testEmail = "example@stackabuse.com"
emailObject = validate_email(testEmail)
print(emailObject.email)
渡された testEmail
は有効なメールアドレスなので、先ほどのコードでは testEmail
変数に格納されたメールアドレスを正規化した形で出力しています。
example@stackabuse.com
注意: 先ほどの例では、もともと正規化されていたため、testEmail
に格納されているアドレスと同じものが出力されています。
正規化されていない形のメールを validate_email()
メソッドに渡すと、期待通りに正規化されたメールアドレスが返されます。
元の testEmail
を "example@STACKabuse.com"
に変更しても、正規化されているので、前のコードは同じ出力となります。
example@stackabuse.com
一方、 validate_email()
メソッドに無効なメールアドレスを渡すと、先ほどのコードでは対応するエラーメッセージが表示されます。
次の testEmail
の例は、構文検証には合格しますが、ドメイン ssstackabuse.com
が存在しないため、配送性検証には不合格になります。
testEmail = "example@ssstackabuse.com"
この場合、前のコードでは長いエラーメッセージが表示され、次のようになります。
>> ...
>> raise EmailUndeliverableError("The domain name %s does not exist." % domain_i18n)
email_validator.EmailUndeliverableError: The domain name ssstackabuse.com does not exist.
このプロンプトに基づき、渡されたメールはドメイン名が存在しないため無効であると結論付けることができます。
構文的に無効な電子メールの場合にも対応するメッセージが表示されるので、渡された電子メールアドレスが電子メールアドレスとして必要な形式を満たしていないと簡単に判断することができます。
ここから、よりユーザーフレンドリーで人間が読みやすいエラーメッセージも自動的に抽出することができます。
先ほどのプロンプトからエラーメッセージだけを抽出するには、先ほどのコードを次のように書き換える必要があります。
from email_validator import validate_email, EmailNotValidError
testEmail = "examplestackabuse.com"
try:
# Validating the `testEmail`
emailObject = validate_email(testEmail)
# If the `testEmail` is valid
# it is updated with its normalized form
testEmail = emailObject.email
print(testEmail)
except EmailNotValidError as errorMsg:
# If `testEmail` is not valid
# we print a human readable error message
print(str(errorMsg))
このコードでは、前のプロンプトから抽出された簡単なエラーメッセージだけを出力します。
The domain name ssstackabuse.com does not exist.
注:ここでは EmailNotValidError
クラスを利用しています。
tryブロックでメール検証を実行し、検証に失敗した場合には
exceptブロックでエラーを捕捉するようにしました。
EmailSyntaxError や EmailUndeliverableError
を個別にキャッチする必要はありません。
どちらもキャッチした EmailNotValidError
クラスのサブクラスであり、出力されるエラーメッセージでエラーの種類は容易に判断できるからです。
validate_email() – オプション引数
デフォルトでは、validate_email()
メソッドは1つの引数 – 検証が必要なメールアドレスの文字列表現のみを受け付けますが、他にもいくつかのキーワード引数を受け付けることができます。
- allow_smtputf8 – デフォルト値は
True
で、False
に設定するとvalidate_email()
は国際化されたメールアドレスを検証せず、ASCII文字のみからなるドメイン名だけを検証します (この場合、ドメイン名にはUTF-8文字は許可されません). - check_deliverability – デフォルト値は
True
で、False
に設定すると配信可能性の検証は行われない . - allow_empty_local – デフォルト値は
False
で、True
に設定すると、メールアドレスの空のローカル部分を許可します (例@stackabuse.com
を有効なメールアドレスと見なします)。
ValidatedEmail オブジェクト
メールアドレスの正規化された形式を emailObject.email
としてアクセスしていることにお気づきでしょうか。
これは、有効なメールアドレスが引数として渡されると、 validate_email()
メソッドが ValidatedEmail
オブジェクトを返すからです(以前の例では、 emailObject
変数に格納されていました)。
ValidatedEmailオブジェクトは、正規化されたメールアドレスのさまざまな部分を記述する複数の属性を含んでいます。
そのため、emailObject.emailという
.` 表記を使ってアクセスする必要があります。
一般的に、 ValidatedEmail
オブジェクトの任意の属性にアクセスするには、 variableName.attributeName
を使用します(ここで variableName
は ValidatedEmail
オブジェクトを格納するために使用する変数です)。
例えば、example@sTaCkABUSE.cOm
を validate_email()
メソッドで検証したとします。
結果として得られる ValidatedEmail
オブジェクトには、以下の表で説明するような、興味深く、便利な属性が含まれることになります。
| 属性名 | 値例 | 説明
| email | example@stackabuse.com | 電子メールアドレスの正規化された形式。
|
| ascii_email|example@stackabuse.com| ASCII only form of email
属性。
もし local_part
が何らかの国際化文字を含んでいる場合、この属性は None
に設定されます。
|
| local_part | example | Eメールアドレスの正規化された形式における @
記号の前の文字列です。
|
| ascii_local_part | example | 国際化文字がない場合、この属性は local_part
属性の ASCII only form に設定される。
そうでなければ、None
に設定される。
|
| domain | stackabuse.com | Eメールアドレスの正規化された形式での @
記号の後の文字列です。
非 ASCII 文字を含む場合、 smptutf8
属性は True
でなければなりません。
|
| ascii_domain | stackabuse.com | ASCII only form of domain
属性です。
|
| smtputf8 | True | ブーリアン値。
もし allow_smtputf8=False
引数が validate_email()
メソッドに渡された場合、この引数は False
になり、そうでなければ True
になります。
注意: 上記の属性のASCIIバージョンは、Punycodeエンコーディング構文を使って生成されます。
これは、アプリケーションの国際化ドメイン名(IDNA)で使用するために、Unicode文字列をASCII文字列に変換するために使用されるエンコーディング構文です。
結論
全体として、email-validator
は Python でメールアドレスの検証を行うための素晴らしいツールです。
このガイドでは、このライブラリを使用する際の重要な点をすべてカバーしたので、総合的に理解することができます。
いつ、どのように email-validator
を使うか、また、いつ別のツールを選ぶべきかを理解できるようになるはずです。