Pythonでメールの送受信をしたい場合はimaplibとsmtplibを使います。
ここではimaplibとsmtplibとGoogleアカウントを使ってメールの送受信をやってみましょう。
Gmailでの送受信を解説しますが、Gmailではなくほかのメールアカウントでも送受信は可能です。
smtplibでGmailアカウントへメールを送信する
メールの送信にはsmtplibとMIMETextを使います。
MIMETextはメールのタイトルや本文を作成するモジュールで、smtplibは実際にメール送信を行うために必要なモジュールです。
また、今回はSSL認証を使いますが、smtplibでGmailでメールを送信する場合は送信元アカウントの「安全性の低いアプリのアクセス」をオンにする必要があります。
こちらからONにできます。
オンにしたら次のコードを試してみましょう。
import smtplib
from email.mime.text import MIMEText
from email.utils import formatdate
FROM = '送信元メールアドレス'
PASSWORD = '送信元のアカウントパスワード'
TO = '送信先メールアドレス'
SUBJECT = 'メールの表題'
BODY = 'Pythonからメールを送信しました。'
#メールの内容
msg = MIMEText(BODY)
msg['Subject'] = SUBJECT
msg['From'] = FROM
msg['To'] = TO
msg['Date'] = formatdate()
#メール送信
smtpobj = smtplib.SMTP_SSL('smtp.gmail.com', 465, timeout=10)
smtpobj.login(FROM, PASSWORD)
smtpobj.sendmail(FROM, TO, msg.as_string())
smtpobj.close()
[結果(送信先)]
[結果(送信元)]
無事メールが送信できました。
メールの内容はMIMETextで作成しています。Subjectには表題、From, Toにはそれぞれ送信元メールアドレスと送信先メールアドレスを設定します。
Dateに設定しているformatdate()はRFC 2822という形式の現在日時を返却しします。
メール認証にはsmtplib.SMTP_SSL関数を使います。1つ目の引数にホスト名、2つ目の引数にポート番号、3つ目の引数に接続試行時間の最大値を秒数単位で指定します。
GmailのSMTPサーバー名はsmtp.gmail.com、SMTP(SSL)のポート番号は465なので、それぞれ指定しています。
最後にsendmail()でメールを送信しています。それぞれ送信元メールアドレス、送信先メールアドレス、MIMETextで作成したメール内容をas_string()で文字列に変換したものを渡しています。
MIMEMultipartでファイルを添付して送信する
MIMEMultipartモジュールを使うことでメールにファイルを添付することもできます。
import smtplib
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication #追加
from email.mime.multipart import MIMEMultipart #追加
from os.path import basename #追加
from email.utils import formatdate
FROM = '送信元メールアドレス'
PASSWORD = '送信元のアカウントパスワード'
TO = '送信先メールアドレス'
SUBJECT = 'メールの表題'
BODY = 'Pythonからメールを送信しました。’
#メールの内容
msg = MIMEMultipart()
msg['Subject'] = SUBJECT
msg['From'] = FROM
msg['To'] = TO
msg['Date'] = formatdate()
msg.attach(MIMEText(BODY))
#ファイル添付
path = './memo.txt'
with open(path, 'rb') as f:
txt_file = MIMEApplication(
f.read(),
Name=basename(path)
)
txt_file['Content-Disposition'] = f'attachment; filename="{basename(path)}"'
msg.attach(txt_file)
#メール送信
smtpobj = smtplib.SMTP_SSL('smtp.gmail.com', 465, timeout=10)
smtpobj.login(FROM, PASSWORD)
smtpobj.sendmail(FROM, TO, msg.as_string())
smtpobj.close()
[結果(送信先)]
[結果(送信元)]
先ほど使用したモジュールはそのままに、MIMEApplicationとMIMEMultipartとbasenameというモジュールを追加しました。
MIMEApplicationは添付ファイルを格納するためのモジュールで、MIMEMultipartは添付ファイル付きメールを送信するための規格を提供してくれるモジュールです。
MIMEApplicationでは拡張子つきファイル名が必要なので、basenameも使っています。
追加されたのでは「ファイル添付」の部分です。with openで添付するファイルをバイナリ形式で開き、MIMEApplicationでMIMEMultipartに渡せるようにしています。
バイナリ形式でファイルを開かないと添付ファイルを正常に送信できないので、必ずrbで開きましょう。
実際のメール送信部分は同じです。
imaplibで受信したメールを取得する
imaplibを使うと受信したメールの中身や添付ファイルを取得できます。
先ほど受信したメールの表題と本文を取得し、さらに添付ファイルも取得して書き出してみましょう。
下準備として受信したメールに「work」というラベルを添付します。
import imaplib
import email
import base64
from email.header import decode_header, make_header
ADDRESS = "Gmailのメールアドレス"
PASSWORD = "アカウントパスワード"
imapobj = imaplib.IMAP4_SSL("imap.gmail.com", '993')
imapobj.login(ADDRESS, PASSWORD)
#workラベル下のメールを取得
imapobj.select('work')
typ, data = imapobj.search(None, 'ALL')
#取得したメールから表題と本文を出力し、添付ファイルを同階層に書き出す
for num in data[0].split():
typ, data = imapobj.fetch(num, '(RFC822)')
#メール内容(タイトル、本文、添付ファイルなど)
mail = email.message_from_string(data[0][1].decode('utf-8'))
#表題出力
subject = str(make_header(decode_header(mail["Subject"])))
print(f"タイトル:{subject}")
#本文出力と添付ファイル書き出し
for part in mail.walk():
if part.get_content_maintype() == 'multipart':
continue
filename = part.get_filename()
if not filename:
body = base64.urlsafe_b64decode(part.get_payload().encode('ASCII')).decode('utf-8')
print(f"本文:{body}")
else:
with open('./' + filename, 'wb') as f:
f.write(part.get_payload(decode=True))
print(f"{filename}を保存しました。")
imapobj.close()
[出力結果]
タイトル:メールの表題
本文:Pythonからメールを送信しました。
memo.txtを保存しました。
順を追ってみていきましょう。
まず初めにimaplib()を使ってIMAPサーバーに接続しています。
imaplib.IMAP4_SSLで認証設定を行います。GmailのIMAPサーバー名とIMAP(SSL)のポート番号をそれぞれ渡しています。
実際にログインしているのではimaplib.login()です。1つ目の引数にメールアドレス、2つ目の引数にGmailアカウントのパスワードを指定します。
次にimapobj(中身はIMAP4_SSL)のselect()で取得するメールのラベルを指定します。
今回はworkを指定しましたが、特に何も指定しない場合は全てのメールが対象になります。
実際にメールを取得しているのが次のimapobj.searchです。今回はALLを指定しているので全てのメールを取得していますが、未読のメールのみを対象としたり、表題から抽出するといったことも可能です。
次に取得したメールをfor文で1つずつ取得し、imapobj.fetch()でメールの情報を取得しています。
実際に必要なデータはdata[0][1]に入っています。utf-8でデコードしてemail.message_from_string()でメッセージ内容をstringから扱いやすいMessageインスタンスに変換しています。
このMessageインスタンスのmail変数に必要な情報が全て入っています。
その中からまずは表題を出力します。make_headerで表題の情報を抽出し、utf-8でデコードして出力しています。
次に本文の出力と添付ファイル保存をするため、mailの構成要素(mail.walk())をループして本文と添付ファイルを探しています。
filename()でファイル名が取得できないものを本文、取得できるものを添付ファイルと判定し、本文は必要なエンコード・デコード処理で変換し、添付ファイルはそのまま同階層にファイルを書き出しています。