GMail APIでGMailの不要メールを削除する
プログラムに必要な情報
だいたい全部公式サイトに書いてあった
1. GMail APIの有効化
https://gyazo.com/092bc7cfb5021e9abd33c45604684056
2. credentials.json をプロジェクトルートに置く
3. GMail APIのPythonライブラリインストール
pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib
4. quickstart サンプルを動かしてみる
ブラウザが起動してアクセス許可を求められるので、許可する
https://gyazo.com/6bd91863513e95c3c1b63bed1d91e566
実行結果が表示されたので成功かな
code:shell
(.venv) C:\Project\python3\gmail-delete> python quickstart.py
Labels:
優先度高
その他
CATEGORY_PERSONAL
要対応
IMPORTANT
CHAT
SENT
INBOX
TRASH
DRAFT
SPAM
STARRED
UNREAD
CATEGORY_FORUMS
CATEGORY_SOCIAL
CATEGORY_UPDATES
CATEGORY_PROMOTIONS
5. 続きはリファレンスを読んでね
shimizukawa.icon 分かりやすい導入だった
やりたいこと
検索条件に一致するメールを削除する。できるだけまとめて、速く。
検索条件: after:2018/5/1 before:2018/6/1 from:(Email Bounces) subject:AWS
Google API リファレンスが最初読みづらかった
Users.draft, Users.history, ... と並んでいて、Users?? history?? となったけどとりあえずスルー
https://gyazo.com/a70f2188ec55df381c892160ed3a9f02
Resource ってなんだ -> Users.threads でよく使われるデータ型だった
snippet ってなんだ -> メッセージ(メール本文)の1行目だった
historyId ってなんだ -> historyは操作履歴らしい。とりあえず無視
Users.threads.list で取得されるデータには messages 要素がなさそう
常にこれらのデータが全て揃ってるわけではないらしい
ゴミ箱に入れる
自分のスクリプトを信用できないので、念のためゴミ箱に入れて、目視して大丈夫そうなら削除しよう
Scope の指定があるのでこれを quickstart.py コードに反映する必要がある
https://gyazo.com/4cd0b825620d7f131100e9dcdc768a69
ゴミ箱に入れずにいきなり削除する
ゴミ箱から削除するときはこれを使う
出来たコード
code:clean_gmail.py
import time
from email.utils import parsedate
import pickle
import os.path
from datetime import datetime
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
# If modifying these scopes, delete the file token.pickle.
SCOPES = [
]
def get_service():
creds = None
# The file token.pickle stores the user's access and refresh tokens, and is
# created automatically when the authorization flow completes for the first
# time.
if os.path.exists('token.pickle'):
with open('token.pickle', 'rb') as token:
creds = pickle.load(token)
# If there are no (valid) credentials available, let the user log in.
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(
'credentials.json', SCOPES)
creds = flow.run_local_server()
# Save the credentials for the next run
with open('token.pickle', 'wb') as token:
pickle.dump(creds, token)
service = build('gmail', 'v1', credentials=creds)
return service
def get_trash_id(service):
# Get Trash label
results = service.users().labels().list(userId='me').execute()
labels = results.get('labels', [])
for label in labels:
raise RuntimeError('No Trash label exist.')
def build_meta(r):
m = {'Subject': '', 'Date': datetime(1970, 1, 1)}
m[h'name'] = datetime.fromtimestamp(time.mktime(parsedate(h'value'))) return m
def empty_trash(service):
total_count = 0
start_time = time.time()
# empty trash
trash_id = get_trash_id(service)
results = service.users().threads().list(userId='me', labelIds=trash_id).execute() threads = results.get('threads', [])
for t in threads:
# import html
r = service.users().threads().get(
userId='me', id=t'id', format='metadata' ).execute()
m = build_meta(r)
rate = total_count / (time.time() - start_time)
print(
'EMPTY TRASH: {mDate:%Y/%m/%d %H:%M:%S}, "{mSubject}", {count}, {rate:.2f}count/s'.format( m=m, count=count, rate=rate))
service.users().threads().delete(userId='me', id=t'id').execute() total_count += count
return total_count
def dump_targets_into_trash(service, q):
total_count = 0
start_time = time.time()
# search targets
results = service.users().threads().list(userId='me', q=q).execute()
threads = results.get('threads', [])
for t in threads:
# import html
r = service.users().threads().get(
userId='me', id=t'id', format='metadata' ).execute()
m = build_meta(r)
rate = total_count / (time.time() - start_time)
print(
'DUMP: {mDate:%Y/%m/%d %H:%M:%S}, "{mSubject}", {count}, {rate:.2f}count/s'.format( m=m, count=count, rate=rate))
service.users().threads().trash(userId='me', id=t'id').execute() total_count += count
return total_count
def main():
service = get_service()
print(datetime.now().strftime('%Y/%m/%d %H:%M:%S'))
while empty_trash(service):
pass
print(datetime.now().strftime('%Y/%m/%d %H:%M:%S'))
while dump_targets_into_trash(service, q='from:(Email Bounces) subject:AWS'):
pass
if __name__ == '__main__':
main()
実行結果
code:bash
(.venv) C:\Project\python3\gmail-delete>python gmailapi.py
2019/03/23 16:07:24
EMPTY TRASH: 2018/03/19 09:25:40, "AWS Notification Message", 100, 0.00count/s
EMPTY TRASH: 2018/03/19 07:54:03, "AWS Notification Message", 100, 20.38count/s
...
EMPTY TRASH: 2018/02/14 08:38:09, "AWS Notification Message", 100, 71.77count/s
2019/03/23 16:37:33
DUMP: 2017/12/14 03:34:47, "AWS Notification Message", 100, 0.00count/s
...
DUMP: 2017/10/27 08:59:06, "AWS Notification Message", 100, 75.03count/s
DUMP: 2017/10/27 08:41:08, "AWS Notification Message", 100, 74.84count/s
DUMP: 2017/10/27 06:40:01, "AWS Notification Message", 100, 74.90count/s
...
一応ログの説明
<ACTION>: <対象スレッドの日付>, <サブジェクト>, <スレッド件数>, <実行速度>
ACTION
EMPTY TRASH: ゴミ箱の中身を削除
DUMP: 検索結果をゴミ箱に入れる
実行した結果
速度: 71.62通/1秒 削除(0.014秒/1通)
10分で削除した件数
46,200件
2017/10/27 ~ 12/14 (48日分)
Google API ドキュメントを読む必要がある
GMailのスレッド単位で削除できるので速い
IMAPでの削除 0.46通/秒 (2.16秒/1通) 削除に比べて154倍速い!
/icons/party_parrot.icon/icons/party_parrot.icon/icons/party_parrot.iconやったーーー!! /icons/party_parrot.icon/icons/party_parrot.icon/icons/party_parrot.icon