lisz-works

プログラミングと興味を貴方に

Python3で受信メール件数をPush通知するスクリプト

【スポンサーリンク】

Python

こんにちは、lisです!

あまり使ってないけど、もしメール来てたら知りたい……

そんなサブのサブみたいなメールアドレスを持っていまして……

とはいえ毎回見に行くのも面倒くさい……

ということで、Python3で受信メール件数をPush通知するスクリプトを作ってTermuxのcronに設定して運用することにしました。

環境

  • Termux

Termux内の他ディストリビューションではなく純正環境を使っています。

www.lisz-works.com

Wi-Fi接続した遊び用スマホに入れてるので、家に置いておけばPushbulletを入れてる端末からどこでも情報取得ができます。

作ったもの概要

  • 受信メール(POP3)をチェックする
  • 新規メールがあった場合、Pushbulletで通知する

Pushbulletへの通知はntfyを使用しました。

詳細はこちらをご参照ください。

www.lisz-works.com

なぜ作ったか?

前述もしましたが、あまり使っていないメールアドレスがある。

けど、「もしかしたら」メールが来るかもしれない……

そう思いながら手動でチェックしてせいで

「毎回見に行くの面倒だし、忘れるし、扱い雑だし……」

と悩んでいました(思い出した頃に)。

「メールを通知する仕組みを作ればいいんだ!」

そう思い立って調べたのがきっかけです。

作成したコード

作成したコードはこちら↓

[コードを表示]

import poplib
import email
from email.header import decode_header, make_header
import ntfy.backends.pushbullet

pushbullet_access_token = 'PushbulletAccessToken'

class Mailer:
    def __init__(self):
        self.server = 'server.address.com'
        self.recv_port = 110
        self.address = 'mail@address.com'
        self.password = 'password'
        self.mailinfo_path = '/data/data/com.termux/files/home/work/mail-notify/.mailinfo'
        self.client = self._connect()

    def __del__(self):
        self.client.quit()

    def _connect(self):
        client = poplib.POP3(self.server, self.recv_port)
        client.user(self.address)
        client.pass_(self.password)
        return client

    def get_mail_num(self):
        mail_num = len(self.client.list()[1])
        return mail_num

    def get_msg(self, no):
        content = self.client.top(no, 0)[1]
        msg = email.message_from_bytes(b'\r\n'.join(content))
        return msg

    def get_mails_info(self):
        num = get_mail_num(self.client)
        mails = []
        for i in range(num):
            no = i + 1
            msg = get_msg(self.client, no)
            from_ = str(msg.get('From')).split(' ')[1]
            subject = str(make_header(decode_header(msg.get('Subject'))))
            mail = {
                'no': no,
                'msg': msg,
                'from_': from_,
                'subject': subject,
            }
            mails.append(mail)
        info = { 'mails': mails}
        return info

    def load_mailinfo(self):
        with open(self.mailinfo_path, mode='r') as f:
            data = f.read()
        return int(data)

    def update_mailinfo(self, data):
        with open(self.mailinfo_path, mode='w') as f:
            f.write(data)

def notify_pushbullet(msg, title=''):
    ntfy.backends.pushbullet.notify(title, msg, pushbullet_access_token)

def main():
    mailer = Mailer()
    num = mailer.get_mail_num()
    print(f'mail: {num}')
    before_num = mailer.load_mailinfo()
    if before_num == num:
        return 1
    msg = f'new mail: {num}'
    title = 'NEW MAIL'
    notify_pushbullet(msg, title)
    mailer.update_mailinfo(str(num))
    return 0

if __name__ == '__main__':
    main()

基本的には「まぁこの処理してくれればいいやー」くらいのノリで作ったレベルです。

ちゃんと調べてないけど例外とかは対処していないのでガバ仕様です。

処理の概要

  • 受信メールの件数をチェック
  • メール情報ファイルと件数を比較
  • 件数の方が多ければPushbulletで通知送信
  • メール情報ファイルを更新

メール情報ファイルには、前回の受信メール件数が出力されるようになっています。

無いことを想定して作ってないので、先に0とだけ入力したテキストファイルとして作成しています。

設定する情報

メールはMailerのコンストラクタで下記のような情報を設定しています。

  • self.server: メールサーバのアドレス
  • self.recv_port: 受信ポート番号
  • self.address: メールアドレス
  • self.password: パスワード
  • self.mailinfo_path: メール情報ファイルのパス

Pushbullet (ntfy)はグローバル領域で下記を設定しています。

  • pushbullet_access_token: Pushbulletのアクセストークン

他のアプリでも使えるように、値渡したらPushbulletしてくれるオレオレパッケージ化しちゃえば便利な気がしてきました。

あとコマンドでntfy使う場合、ホームに設定ファイルを置くのでそこからアクセストークン読んできた方がいいんだろうなーと今更思いました。

コンストラクタ/デストラクタ

あまり込み入った作り方をしていないので設定を直書きしているガバ仕様です。

コンストラクタに必要な設定値をセット+メールサーバに接続。

デストラクタで切断しています。

接続→切断はセットで行ったほうがよいようなので、コンストラクタ/デストラクタで実行してもらうことでセットで実行できるようにしています。

メールの情報を取得する関数

get_mails_infoでメールの情報します。

ここでコールしている関数は↓のようなことをしています。

  • get_mail_num
    • メールの数を取得します
  • get_msg
    • 指定したメールを取得します
    • ここで取得するオブジェクトがメール1件分の情報になります
    • この中身を見るとタイトル等、メールの情報が見れます

このスクリプトの目的としてはメール本文は不要なので取得していません。

get_msgでtop()を使ってメッセージを取得していますが、これだとメール本文は取得できないようです。

top()の代わりにretr()で取得すると、本文も見えるっぽいです(曖昧)。

Pushbullet (ntfy)

ntfyを使ってPushbulletで「xx件新着メール来てるよ!」と知らせるためPush通知しています。

詳細は過去記事をご参照くださいませ。

www.lisz-works.com

cronを設定する

このスクリプトを定期実行してもらうためにcronを設定しています。

適当に定期実行してもらうために↓のように設定しています。

$ crontab -l
0 7 * * * python /data/data/com.termux/files/home/work/mail-notify
0 17 * * * python /data/data/com.termux/files/home/work/mail-notify

詳細は過去記事をご参照くださいませ。

www.lisz-works.com

参考

コチラを参考にしました。ありがとうございました!

myafu-python.com docs.python.org qiita.com www.itbook.info