2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PythonでGmailからメールを取得してExcelに保存する自動化スクリプト

Last updated at Posted at 2025-01-28

PythonでGmailからメールを取得してExcelに保存する方法

この記事では、Pythonを使ってGmailのメールを取得し、Excelファイルに保存する方法を紹介します。特に、過去に取得したメールを再度保存しないようにする方法や、エラーハンドリング、メールの日時フォーマットの処理を含めて解説します。

使用するライブラリ

  • imaplib: GmailのIMAPサーバーに接続し、メールを取得するためのライブラリです。
  • email: メールの解析と操作を行います。
  • openpyxl: Excelファイルの読み書きに使用します。
  • pytz: タイムゾーンの操作をサポートします。
  • re: 正規表現を使用して文字列を処理します。

1. メールの取得

まず、GmailのIMAPサーバーに接続して、メールを取得します。ここでは、全てのメールを取得し、過去に保存したメールをスキップするようにしています。

def fetch_emails(last_saved_date):
    with imaplib.IMAP4_SSL("imap.gmail.com") as mail:
        mail.login(email_user, app_password)
        mail.select("inbox")  # Inboxを選択
        
        status, messages = mail.search(None, "ALL")
        email_ids = messages[0].split()

        emails = []
        for email_id in email_ids:
            status, msg_data = mail.fetch(email_id, "(RFC822)")
            for response_part in msg_data:
                if isinstance(response_part, tuple):
                    msg = email.message_from_bytes(response_part[1])
                    subject, encoding = decode_header(msg["Subject"])[0]
                    if isinstance(subject, bytes):
                        subject = subject.decode(encoding or "utf-8")
                    from_ = msg.get("From")
                    date = msg.get("Date")
                    # メールの日時を解析
                    date_cleaned = re.sub(r" \(.*?\)", "", date)  # "(UTC)" を削除
                    date_cleaned = date_cleaned.replace("GMT", "+0000")  # "GMT" を "+0000" に変換
                    
                    # 日付をパース
                    try:
                        email_date = datetime.strptime(date_cleaned, "%a, %d %b %Y %H:%M:%S %z")
                    except ValueError:
                        print(f"日付解析エラー: {date_cleaned}")
                        continue
                    
                    if email_date <= last_saved_date:
                        continue
                    
                    body = ""
                    if msg.is_multipart():
                        for part in msg.walk():
                            content_type = part.get_content_type()
                            if content_type == "text/plain":
                                body = part.get_payload(decode=True).decode("utf-8")
                                body = extract_reply_body(body)
                                break
                    else:
                        body = msg.get_payload(decode=True).decode("utf-8")
                        body = extract_reply_body(body)
                    
                    emails.append((subject, from_, date, body))
        return emails

2. メールの保存

取得したメールをExcelファイルに保存する関数です。ファイルが存在する場合、最後に保存した日時を取得して、それ以降のメールだけを保存します。

def save_to_excel(emails, start_date):
    try:
        wb = openpyxl.load_workbook(excel_file)
        sheet = wb.active
    except FileNotFoundError:
        wb = openpyxl.Workbook()
        sheet = wb.active
        sheet.append(["Subject", "From", "Date", "Body"])

    dates = [row[2] for row in sheet.iter_rows(min_row=2, values_only=True) if row[2]]  # 日付列を取得
    if dates:
        last_saved_date = max(dates)
        if isinstance(last_saved_date, str):
            last_saved_date = datetime.strptime(last_saved_date, "%a, %d %b %Y %H:%M:%S %z")
    else:
        last_saved_date = start_date

    if last_saved_date.tzinfo is None:
        last_saved_date = last_saved_date.replace(tzinfo=datetime.timezone.utc)

    for subject, from_, date, body in emails:
        date_cleaned = re.sub(r" \(.*?\)", "", date)
        date_cleaned = date_cleaned.replace("GMT", "+0000")
        try:
            email_date = datetime.strptime(date_cleaned, "%a, %d %b %Y %H:%M:%S %z")
        except ValueError:
            print(f"日付解析エラー: {date_cleaned}")
            continue
        
        if email_date <= last_saved_date:
            continue
        sheet.append([subject, from_, date, body])

    wb.save(excel_file)
    print("新しいメールをExcelファイルに保存しました。")

3. メールの本文から返信部分を削除

返信メールの場合、メール本文に「On ... wrote:」のような返信部分が含まれます。これを削除して、純粋な本文だけを取得します。

def extract_reply_body(body):
    reply_index = body.find("On")  # 通常、返信部分は「On ... wrote:」という形式
    if reply_index != -1:
        return body[:reply_index].strip()
    return body.strip()

4. 初回実行時と次回以降の動作

初回実行時には、start_date を設定して、その日時以降のメールを取得します。次回以降は、Excelファイルに保存された最終日時を基準に、前回保存した日時以降のメールを取得します。

※データ取得
dates = [row[2] for row in sheet.iter_rows(min_row=2, values_only=True) if row[2]]について
https://qiita.com/ellyyyy/items/b363113f599e67665a4d

if __name__ == "__main__":
    start_date = datetime(2025, 1, 1, 0, 0, 0)

    if start_date.tzinfo is None:
        start_date = start_date.replace(tzinfo=pytz.utc)

    emails = fetch_emails(start_date)
    if emails:
        save_to_excel(emails, start_date)
    else:
        print("新しいメールがありませんでした。")

    try:
        wb = openpyxl.load_workbook(excel_file)
        sheet = wb.active
        dates = [row[2] for row in sheet.iter_rows(min_row=2, values_only=True) if row[2]]
        if dates:
            last_saved_date = max(dates)
            emails = fetch_emails(last_saved_date)
            if emails:
                save_to_excel(emails, last_saved_date)
            else:
                print("新しいメールがありませんでした。")
    except FileNotFoundError:
        print("Excelファイルが見つかりません。最初にメールを保存してください。")

処理フロー

A[初回実行時: 開始日時指定] --> B[fetch_emails関数]
B --> C[IMAPサーバーに接続]
C --> D[メールのリストを取得]
D --> E[各メールの解析]
E --> F[日付をパースして保存対象のメールをフィルタリング]
F --> G[メールの件名、送信者、本文を取得]
G --> H[メールデータをリストに追加]
H --> I[保存対象のメールがあればsave_to_excel関数]
I --> J[Excelファイルを開くまたは新規作成]
J --> K[ヘッダー追加]
K --> L[既存のメールの日時を確認]
L --> M[新しいメールをフィルタリングしてExcelに保存]
M --> N[Excelファイルを保存]

まとめ

このコードでは、最初に指定した日時からメールを取得し、その後はExcelファイルに保存されている最終保存日時を基準にして新しいメールを取得・保存します。メールの日時や本文に関するエラーハンドリングも行い、メールの重複保存を防いでいます。

この方法を使えば、Gmailのメールを効率よく管理し、Excelで簡単に保存・整理できます。

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?