こんにちは、DXCEL WAVEの運営者(@dxcelwave)です!
【Python】受信メール解析ツールとは?
受信メール解析ツールとは、「人手を介さずに受信したメールをチェックし、メールの内容に応じて必要なアクションを自動で行ってくれるツール」です。主な用途としては下記があります。
業務効率化やマーケティング用途でのメール解析
メール解析の自動化に伴う一番の目的は「作業効率化」と「マーケティングの高度化」です。
例えばマーケティング用途で、商品のメール問い合わせから要望やクレームを集計したいと考えたとします。この時、メールを1つずつ手作業で確認していくとメール数によっては非常に手間がかかってしまいます。メール解析を利用すると、例えばメール件名や本文を一度にデータ抽出し、キーワードや問い合わせカテゴリ毎に一括集計することができるようになります。
スパム・迷惑メール対策でのメール解析
メールの本文解析を駆使することで、例えば「大セールス」「期間限定お得!」などの特定キーワードを含むメールを一括スパムメール扱いにすることもできるようになります。このようにメール解析はセキュリティ強化目的においても非常に有効な手段と言えます。
「メール業務の自動化の意義」「メール自動化でできること」を詳しく知りたい方は、まずこちらの記事をご覧になられることを推奨します。
【RPA】メール確認・メルマガ配信業務の自動化・マーケティングオートメーションの実現方法を徹底解説
面倒なメール作業をRPAで自動化したいが方法が分からない。そもそもメール作業の何が自動化できるか分からない。本記事では、このような疑問に答えます。また、メールマーケティング・マーケティングオートメーション(MA)の実現方法も詳しくご紹介しています。
【参考】手軽に利用可能なメール配信システム・おすすめ学習法
Python言語で構築することに障壁がある方向けに、ノーコードかつ手軽にメール配信を実施できるシステムを紹介します。Pythonで実装したメール機能と上記システム機能を比較し、お好みの方法を選択することをおすすめします。
Pythonを活用してメール受信・配信タスクの自動化手法を深く学びたい方向けに、おすすめの教材も併せてご紹介します。
メール解析の対象要素(ヘッダー・ボディ)について
メールのヘッダーとは、受信したメールがいつ・どこから・どのような経路で送信されたのか記録したものです。メールのボディとは、メールの本文を指します。メール解析では、これらヘッダー・ボディ情報を解析していくことになります。主に取り扱う情報を整理すると下記のようになります。
メールヘッダー:代表的な取り扱い情報
- 電子メールの識別番号(Message-ID)
- メール作成時刻(Created At)
- 送信元(From)のメールアドレス
- 送信先(To)のメールアドレス
- 件名(Subject)
- メール配信経路(Received)
- メール配信エラー時の戻り先(Return-Path)
メールボディ:代表的な取り扱い情報
- メール本文
Gmailを用いた受信メール解析ツールの作成手順
上図にメール解析ツール構築の全体プロセスを示します。
まず、IMAPサーバーにログインし、解析したいメールを検索します。続いて、メール情報に応じて必要アクションを付与するといった流れです。今回紹介するプログラミング手法は、メール解析の中核となる①〜③を中心に解説しています。
【参考】メール送受信に伴う通信規定
下記通信規定の用語は頻繁に用います。事前に確認しておきましょう。
IMAP
IMAP(Internet Message Access Protocol)とは、メール受信のためのプロトコルです。IMAPの場合、メールはサーバ上での保管が特徴であるため、メールのステータス(既読・未読・削除)等も全てサーバで管理されます。
SSL/TLS
SSL(Secure Sockets Layer)およびTLS(Transport Layer Security)は、インターネット上のデータを暗号化し、送受信するためのプロトコルです。個人情報やクレジットカード、パスワードなどのデータを暗号化し、データの改ざんや盗聴を防止します。
【Python】メール解析に必要なライブラリ・インストール方法
本記事では、下記ライブラリを使用します。事前にインストールしておきましょう。
IMAPClient(IMAPサーバー接続に利用)
pip install imapclient
backports.ssl(SSL暗号化に利用)
pip install backports.ssl
pyOpenSSL(SSL暗号化に利用)
pip install pyOpenSSL
pyzmail36(メール解析に利用)
pip install pyzmail36
Gmailのアプリパスワードを事前に取得する
Gmailのアプリパスワードを作成していない場合、事前作成が必要です。下記の手順に従い、アプリパスワードを生成しましょう。(※普段Gmailにログインするパスワードとアプリパスワードは別のものです。)
- Googleアカウントを開く(上図参照)
- セキュリティを開く
- 2段階認証プロセスをONにする
- アプリパスワードを生成する
【Python】受信メール解析ツールを実際に作成
それでは実際にPythonを用いて受信メール解析ツールを作成していきましょう!
IMAPサーバー接続&SSL暗号化
まず、サーバー接続を解説します。メールプロバイダを指定、SSL暗号化し、IMAPClientオブジェクトを生成することでIMAPサーバーに接続します。
# ライブラリ読込
import imapclient
from backports import ssl
from OpenSSL import SSL
# SSL暗号化
context = ssl.SSLContext(SSL.TLSv1_2_METHOD)
# IMAP接続用のオブジェクト作成
imap = imapclient.IMAPClient("imap.gmail.com", ssl=True, ssl_context=context)
今回はGmailを利用していますが、下記IMAPサーバー名を記載すると別プロバイダーの指定も可能です。日頃から活用しているプロバイダーを指定すると良いでしょう。
プロバイダー | SMTPサーバー名 |
---|---|
Gmail | imap.gmail.com |
Yahoo Mail | imap.mail.yahoo.com |
Outlook.com | imap-mail.outlook.com |
IMAPサーバーにログイン
IMAPClientオブジェクト生成後、login()メソッドでIMAPサーバーにアクセスします。login()メソッドには、第一引数にメールアドレス、第二引数にパスワードを渡します。
# ログイン情報
my_mail = "メールアドレスを入力"
app_password = "パスワードを入力"
# IMAPサーバーログイン
imap.login(my_mail,app_password)
メール検索&解析
ログイン後、下記の2ステップを跨いで特定のメールを探し出します。
- メールを検索する対象フォルダを指定
- メール検索キーワードをもとに検索実行
対象の受信メールフォルダを指定
メールアカウントにどのようなフォルダが存在するか確認が必要な場合、以下のように記載することでフォルダ名を確認できます。
# 全てのメールフォルダ情報を表示
imap.list_folders()
# 出力結果
# [((b'\\HasNoChildren',),b'/','INBOX'),
# ((b'\\HasChildren',b'\\Noselect'),b'/','[Gmail]'),
# ((b'\\All', b'\\HasNoChildren'),b'/','[Gmail]/All Mail'),
# ((b'\\Drafts', b'\\HasNoChildren'),b'/','[Gmail]/Drafts'),
# ((b'\\HasNoChildren',b'\\Important'),b'/','[Gmail]/Important'),
# ((b'\\HasNoChildren',b'\\Sent'),b'/','[Gmail]/Sent Mail'),
# ((b'\\HasNoChildren',b'\\Junk'),b'/','[Gmail]/Spam'),
# ((b'\\Flagged',b'\\HasNoChildren'),b'/','[Gmail]/Starred'),
# ((b'\\HasNoChildren',b'\\Trash'),b'/','[Gmail]/Trash')]
下記のように、IMAPClientオブジェクトselect_folder()メソッドにフォルダ名を渡し、メール検索対象フォルダを指定します。
# メールフォルダを指定
imap.select_folder("INBOX", readonly=True)
今回第一引数にフォルダ名(“INBOX”)、第二引数にreadonly=True(メールの編集や削除操作をできなくする)と指定します。第二引数はメール確認が目的であれば、通常このように記載します。
メール検索キーワードをもとに、メール検索実行
フォルダ選択後、下記のように記載してメール検索を実行してみましょう。
import pyzmail
import pandas as pd
#① 検索キーワードを設定 & 検索キーワードに紐づくメールID検索
KWD = imap.search(["ここに検索キーワードを記載する"])
#② メールID→メール本文取得
raw_message = imap.fetch(KWD,["BODY[]"])
ここで、メールの検索方法は下記の表を参照ください。
検索方法 | 検索キーワード記載例 |
---|---|
対象フォルダの全メール検索 | [“ALL”] |
対象期間 | [“SINCE”, “開始日”, “BEFORE”, “終了日”] |
対象日 | [“ON”, “対象日”] |
メールアドレス | [“FROM”, “差出人メールアドレス”] [“TO”, “メールアドレス”] [“CC”, “メールアドレス”] [“BCC”, “メールアドレス”] |
既読ステータス | [“SEEN”] (既読) [“UNSEEN”] (未読) |
フラグ(重要)ステータス | [“FLAGGED”] (フラグあり) [“UNFLAGGED”] (フラグなし) |
返信ステータス | [“ANSWERED”] (返信済み) [“ANSWERED”] (未返信) |
除外(NOT) | [“NOT”, “検索したくない条件”] |
追加(OR) | [“OR”, “追加検索したい条件1″,”追加検索したい条件1”] |
以下検索方法を具体的に紹介します。用途に応じて①部分を書き換えましょう。
2021年1月1日〜2021年3月30日まで期間で未読メールを取得
#① 検索キーワードを設定 & 検索キーワードに紐づくメールID検索
KWD = imap.search(["SINCE","01-Jan-2021", "BEFORE", "30-Mar-2021", "UNSEEN"])
2021年1月1日に”test@gmail”から届いたメールを取得
#① 検索キーワードを設定 & 検索キーワードに紐づくメールID検索
KWD = imap.search(["ON","01-Jan-2021", "FROM", "test@gmail.com"])
“test@gmail”または”test2@gmail.com”から届いたメールを全取得
#① 検索キーワードを設定 & 検索キーワードに紐づくメールID検索
KWD = imap.search(["OR", "FROM", "test@gmail.com", "FROM", "test2@gmail.com"])
検索したメールを解析
検索したメール解析結果を出力します。Pandasのデータフレームを用いて宛先、件名、本文の情報を抽出してみましょう。
#解析メールの結果保存用
From_list = []
Cc_list = []
Bcc_list = []
Subject_list = []
Body_list = []
#検索結果保存
for j in range(len(KWD)):
#特定メール取得
message = pyzmail.PyzMessage.factory(raw_message[KWD[j]][b"BODY[]"])
#宛先取得
From = message.get_addresses("from")
From_list.append(From)
Cc = message.get_addresses("cc")
Cc_list.append(Cc)
Bcc = message.get_addresses("bcc")
Bcc_list.append(Bcc)
#件名取得
Subject = message.get_subject()
Subject_list.append(Subject)
#本文
Body = message.text_part.get_payload().decode(message.text_part.charset)
Body_list.append(Body)
#④出力
table = pd.DataFrame({"From":From_list,
"Cc":Cc_list,
"Bcc":Bcc_list,
"Subject":Subject_list,
"Body":Body_list,
})
print(table)
これでメール解析が完了しました。あとは、解析結果に応じて必要アクションを付与するのみです。
本記事において、対応アクションのプログラミング方法は割愛しています。実際の業務ではPandasで得れらた情報をもとにメール集計や情報連携のプログラムを追加してみると良いでしょう。メールの削除方法に関しては以下ご紹介します。
メールの解析結果に対してアクションを付与(メールの削除)
メールを削除するには、IMAPClientオブジェクトdelete_messages()メソッドを活用します。その際、メール検索時に取得したメールID(KWDから取得)を渡し、メールを削除します。
# フォルダを指定
imap.select_folder("フォルダ名を記載",readonly=False)
# 検索実行
KWD = imap.search(["検索方法を記載"])
# 削除
imap.delete_messages(KWD)
# メール完全削除
imap.expunge()
ここで重要な点として、メール検索時にフォルダ指定する際は、readonly=Falseとすることです。これによってメールが削除可能になります。
IMAPから接続を遮断
メール解析が終わったら、IMAPClientオブジェクトlogout()メソッドを用いてIMAPサーバーから遮断しましょう。
imap.logout()
【まとめ】Pythonメール解析の全体コード
最後に本日学習したコードを関数の形で全量記載します。
第一引数にメールアドレス、第二引数にパスワード、第三引数にフォルダ名、第四引数にメール検索条件を渡す関数です。戻り値として解析したメール情報(宛先情報、件名、メール本文)を渡します。
""" ライブラリ読込 """
import imapclient
from backports import ssl
from OpenSSL import SSL
import pyzmail
import pandas as pd
pd.options.display.max_columns = None
pd.options.display.max_rows = None
""" (要編集) 引数指定 """
#ログイン情報
my_mail = "メールアドレスを入力"
app_password = "パスワードを入力"
#メール検索条件
FolderName = "フォルダ名を入力"
Search_KWD = ["検索条件を入力"]
""" 関数定義 """
def Get_Mail(my_mail, app_password, FolderName, Search_KWD):
""" ① IMAPサーバー接続 & SSL化 """
context = ssl.SSLContext(SSL.TLSv1_2_METHOD)
# context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
imap = imapclient.IMAPClient("imap.gmail.com", ssl=True, ssl_context=context)
""" ② IMAPログイン """
imap.login(my_mail,app_password)
""" ③ メール検索 """
#対象の受信メールフォルダを指定
imap.select_folder(FolderName, readonly=True)
#検索キーワードを設定 & 検索キーワードに紐づくメールID検索
KWD = imap.search(Search_KWD)
#メールID→メール本文取得
raw_message = imap.fetch(KWD,["BODY[]"])
""" ④ 解析結果保存 """
#検索結果保存用
From_list = []
Cc_list = []
Bcc_list = []
Subject_list = []
Body_list = []
#メール解析
for j in range(len(KWD)):
#特定メール取得
message = pyzmail.PyzMessage.factory(raw_message[KWD[j]][b"BODY[]"])
#宛先取得
From = message.get_addresses("from")
From_list.append(From)
Cc = message.get_addresses("cc")
Cc_list.append(Cc)
Bcc = message.get_addresses("bcc")
Bcc_list.append(Bcc)
#件名取得
Subject = message.get_subject()
Subject_list.append(Subject)
#本文
Body = message.text_part.get_payload().decode(message.text_part.charset)
Body_list.append(Body)
#Pandas データフレーム
table = pd.DataFrame({"From":From_list,
"Cc":Cc_list,
"Bcc":Bcc_list,
"件名":Subject_list,
"本文":Body_list,
})
#IMAPログアウト
#imap.logout()
return table
最後に以下を実行し、動作確認してみましょう。
# ログイン情報
my_mail = "メールアドレスを入力"
app_password = "パスワードを入力"
# メール検索条件
FolderName = "INBOX"
Search_KWD = ["SINCE","01-Jan-2021", "BEFORE", "30-Mar-2021"]
# 関数実行
Get_Mail(my_mail, app_password, FolderName, Search_KWD)
【参考】Pythonで面倒な作業を自動化!手法一挙公開中!
当サイトでは日々面倒な作業をPythonで自動化する方法を多数配信しております。日々の作業が飛躍的効率化できること間違いなしですので、以下気になった記事があれば併せてご覧ください。
【面倒なタスクをPythonで解決!】作業効率化の人気記事一覧
【参考】Pythonとは?・実現できること
最後に
お問い合わせフォーム
上記課題に向けてご気軽にご相談下さい。
お問い合わせはこちら