IMAP Pythonでメール受信を行う方法 email imaplib

なおこのこだわり
スポンサーリンク

挨拶と前書き

みなさんこんにちは、ウーバーイーツ初日で全身が筋肉痛になっているなおこです。

今回は、Pythonを用いてメール受信を行い、内容をLINEに転送するというのをやっていきたいと思います。

メール受信というとIMAPやPOPなどが挙げられると思いますが、今回はIMAPを使用する方法をご紹介します。

必要な技術や知識

  • IMAP関連の基礎
  • pythonの基礎

本題

先に完成したプログラムを見たいんじゃって人は下記の+ボタンをタップやクリックで表示


import requests
import imaplib
import email
from email.header import decode_header, make_header

mail=imaplib.IMAP4_SSL('メールサーバーのアドレス',ポート番号) 
mail.login('メールアドレス','パスワード')
mail.select('inbox')

type,data=mail.search(None,'ALL')	

for i in data[0].split():	
    ok,x = mail.fetch(i,'RFC822')	
    ms   = email.message_from_string(x[0][1].decode('iso-2022-jp'))

    // 取得したデータを変数に入れる。
    to_      = str(make_header(decode_header(ms["To"])))
    date_    = str(make_header(decode_header(ms["Date"])))
    from_    = str(make_header(decode_header(ms["From"])))
    subject_ = str(make_header(decode_header(ms["Subject"])))

    // マルチパート処理 
    if ms.is_multipart() is False:
        payload = ms.get_payload(decode=True) 
        charset = ms.get_content_charset()
        
        if charset is not None:
            payload = payload.decode(charset, "ignore")
    else:
        for part in ms.walk():
            payload = part.get_payload(decode=True)
            if payload is None:
                continue
            charset = part.get_content_charset()
            if charset is not None:
                payload = payload.decode(charset, "ignore")


    print(to_)
    print(date_)
    print(from_)
    print(subject_)
    print(payload) 



    url = 'https://notify-api.line.me/api/notify'
    token = 'LINEトークン'
    headers = {'Authorization': f'Bearer {token}'}
    data = {'message': f'message: {to_}\n{date_}\n{from_}\n{subject_}\n{payload}'}
    requests.post(url, headers=headers,data=data )


    mail.store(i, '+FLAGS', r'(\Deleted)')


mail.close()
mail.logout()

LINE Notifyの発行

取得したメールをLINEに転送するをお手軽実装できるLINE Notifyを使用していきたいと思います。

そのためAPIの発行を行います。下記のサイトにアクセスし右上のボタンからログインします。

LINE Notify
LINE NotifyはGitHub,IFTTT,MackerelなどのWebサービスからの通知を、LINEで受信することが出来る便利なサービスです。

ログインしたら、トークンを発行するボタンからアクセストークンを発行します。

フォームに必要な情報を入力し発行するボタンを押します。

発行したトークンは一度しか表示されないので下記の画面でメモしておきましょう。

使うライブラリやモジュールの準備

使うライブラリとかモジュールをリストにしてみました

  • imaplib
  • email
  • requests

python3ではimaplibやemailは標準ライブラリのため別途pipでインストールする必要はありません

imaplib --- IMAP4 プロトコルクライアント — Python 3.9.4 ドキュメント

requestsに関してはメール受信を行うだけであれば必要ないですが、LINEに転送するのに使うのでpipなどでインストールしておきましょう。

pip install requests

プログラムを順番にかいていく

ライブラリの読み込み

先程インストールしておいたライブラリや標準ライブラリを読み込みしておきます。

import requests
import imaplib
import email
from email.header import decode_header, make_header

メールサーバー接続する

SSL環境のメールサーバーに接続してログインします。

その後selectで参照する箇所を選びます。今回はinboxを選びました。

次にsearchで条件を指定してメール一覧を取得します。(未読のみなどの場合はここで調整)

//メールをサーバーに接続する
mail=imaplib.IMAP4_SSL('メールサーバーのアドレス',ポート番号) 
mail.login('メールアドレス','パスワード')

// 届いたメールを確認するためにinboxを選択。
mail.select('inbox')

//メールを一覧取得しtype変数とdata変数に代入
type,data=mail.search(None,'ALL')	

メール一覧から本文を取得、LINEに転送

メール一覧の配列を元にfor文でループを開始します。

ループ内で行う処理は下記のようになります。

  • 先程取得したデータを元にループを行います。
  • メールをデコードする
  • 取得した本文以外のデータを変数に入れる
  • 本文がマルチパートじゃないの場合とマルチパートの条件で処理し変数に入れる。
  • 取得したデータを表示
  • ラインに転送
  • メールを削除
//ループを開始
for i in data[0].split():	
    // メールをデコードする
    ok,x = mail.fetch(i,'RFC822')	
    ms   = email.message_from_string(x[0][1].decode('iso-2022-jp'))

    // 取得したデータを変数に入れる。
    to_      = str(make_header(decode_header(ms["To"])))
    date_    = str(make_header(decode_header(ms["Date"])))
    from_    = str(make_header(decode_header(ms["From"])))
    subject_ = str(make_header(decode_header(ms["Subject"])))

    // マルチパート処理 
    // マルチパートじゃなかった場合
    if ms.is_multipart() is False:
        payload = ms.get_payload(decode=True) 
        charset = ms.get_content_charset()
        
        if charset is not None:
            payload = payload.decode(charset, "ignore")

    // それ以外(マルチパートだった場合)
    else:
        for part in ms.walk():
            payload = part.get_payload(decode=True)
            if payload is None:
                continue
            charset = part.get_content_charset()
            if charset is not None:
                payload = payload.decode(charset, "ignore")



// デバック用だけど内容を表示する
    print(to_)
    print(date_)
    print(from_)
    print(subject_)
    print(payload) 


LINE NotifyのAPIを使ってメールの内容をLINEに送ります。

最初に取得したアクセストークとAuthorization ヘッターに付与して内容をドキュメントを見ながら設定します。

最後にPOSTで送ります。

LINE Notify
LINE Notify allows you to send web notifications from GitHub, IFTTT, Mackerel, and more directly to your LINE chats.
//LINEに転送する

    url = 'https://notify-api.line.me/api/notify'
    token = 'LINEトークン'//最初に取得したアクセストークンを記述
    headers = {'Authorization': f'Bearer {token}'}
    data = {'message': f'message: {to_}\n{date_}\n{from_}\n{subject_}\n{payload}'} //送りたい内容を記述
    requests.post(url, headers=headers,data=data )

ループの最後にメールを削除します。(このとき未読や既読で判定する場合は削除ではなくフラグを付与する形に変更してください。)




    //メールを削除
    mail.store(i, '+FLAGS', r'(\Deleted)')

メールサーバーから切断する

最後にメールサーバーから切断し、ログアウトしたら完了です。




mail.close()
mail.logout()

完成したプログラム


import requests
import imaplib
import email
from email.header import decode_header, make_header

mail=imaplib.IMAP4_SSL('メールサーバーのアドレス',ポート番号) 
mail.login('メールアドレス','パスワード')
mail.select('inbox')

type,data=mail.search(None,'ALL')	

for i in data[0].split():	
    ok,x = mail.fetch(i,'RFC822')	
    ms   = email.message_from_string(x[0][1].decode('iso-2022-jp'))

    // 取得したデータを変数に入れる。
    to_      = str(make_header(decode_header(ms["To"])))
    date_    = str(make_header(decode_header(ms["Date"])))
    from_    = str(make_header(decode_header(ms["From"])))
    subject_ = str(make_header(decode_header(ms["Subject"])))

    // マルチパート処理 
    if ms.is_multipart() is False:
        payload = ms.get_payload(decode=True) 
        charset = ms.get_content_charset()
        
        if charset is not None:
            payload = payload.decode(charset, "ignore")
    else:
        for part in ms.walk():
            payload = part.get_payload(decode=True)
            if payload is None:
                continue
            charset = part.get_content_charset()
            if charset is not None:
                payload = payload.decode(charset, "ignore")


    print(to_)
    print(date_)
    print(from_)
    print(subject_)
    print(payload) 



    url = 'https://notify-api.line.me/api/notify'
    token = 'LINEトークン'
    headers = {'Authorization': f'Bearer {token}'}
    data = {'message': f'message: {to_}\n{date_}\n{from_}\n{subject_}\n{payload}'}
    requests.post(url, headers=headers,data=data )


    mail.store(i, '+FLAGS', r'(\Deleted)')


mail.close()
mail.logout()

完成したプログラムを実行してみます。

まずは誰から送られたと仮定してメールを送ります。

プログラムを実行します。

するとLINEに届く!

これをあとはcrontabなどで回せばメールが来た瞬間に転送したりできるわけですね。

最後に

実際に本番環境で実装する場合は偽装されてるかのチェックやiso-2022-jp以外の対応、crontabではなくサービス化なども必須かと思います。

今回もサムネイルを描いてみました。メールは世界を飛ぶイメージがあるのでそれを表現してみました。

(背景はAC写真の素材でごまかしました)

それではそれではby

コメント

タイトルとURLをコピーしました