Py学习  »  MagTun  »  全部回复
回复总数  1
5 年前
回复了 MagTun 创建的主题 » Python:以pdf格式从标签(gmail)下载所有电子邮件

我尝试了Ali Nuri Seker的建议,但没有成功:
-eml2pdf:不在Windows上工作
-eml到pdf:Mime类型错误
-pyPdf:构建整个设计所需的工作太多 -gmail到pdf:一些电子邮件的代码中存在错误(参见github中提到的错误)

  1. 将电子邮件另存为.eml email.generator.Generator
  2. 使用 eml-to-pdf-converter (不是基于python,而是开源的GUI)将.eml文件转换为pdf文件(基本上只需删除包含.eml文件的文件夹,单击按钮,就可以得到pdf文件。它甚至可以与子文件夹一起使用!)

可以找到更详细的脚本 here


# source  = https://developers.google.com/gmail/api/quickstart/python?authuser=2

# In brief:
# this script will connect to your gmail account and download as .eml file your email from a specified label. 
# then you can convert the .eml files to pdf :  https://github.com/nickrussler/eml-to-pdf-converter

# set up
#  1) save this script in a folder
#  2) save the script "get labels id.py" in the same folder
#  3) go to this link https://developers.google.com/gmail/api/quickstart/python and click on "Enable the gmail API", then click on "Download client configuration" and save this .json file in the same folder as this script
#  4) GMAIL API doesn't use Label name but ID so you need to run the script "get labels id.py" and to copy the ID for the label you need (the firt time, you will be ask the persmission on  a consent screen, accept it with the account where you want to download your email)  
#  5) copy your label id below in custom var 
#  6) run this script and your emails will be saved as .eml file in a subfolder "emails as eml"

# connect to gmail api 
from __future__ import print_function
import pickle
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request

# decode response from Gmail api and save a email
import base64
import email

#for working dir and path for saving file
import os

# CUSTOM VAR 
labelid = "Label_18"  # change your label id

# set working directory  https://stackoverflow.com/a/1432949/3154274
abspath = os.path.abspath(__file__)
dname = os.path.dirname(abspath)
os.chdir(dname)
print("working dir set to ", dname)

# create folder to save email 
emailfolder= dname+"\emails as eml"
if not os.path.exists(emailfolder):
    os.makedirs(emailfolder)


# If modifying these scopes, delete the file token.pickle.
SCOPES = ['https://www.googleapis.com/auth/gmail.readonly']

def main():

    # create the credential the first tim and save then in token.pickle
    creds = None
    if os.path.exists('token.pickle'):
        with open('token.pickle', 'rb') as token:
            creds = pickle.load(token)
    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()
        with open('token.pickle', 'wb') as token:
            pickle.dump(creds, token)

    #create the service 
    service = build('gmail', 'v1', credentials=creds)


    # get the *list* of all emails in the labels (if there are multiple pages, navigate to them)
    #*************************************
    #  ressources for *list* email by labels
    # https://developers.google.com/resources/api-libraries/documentation/gmail/v1/python/latest/index.html 
    # https://developers.google.com/resources/api-libraries/documentation/gmail/v1/python/latest/gmail_v1.users.messages.html#list
    # example of code for list: https://developers.google.com/gmail/api/v1/reference/users/messages/list?apix_params=%7B%22userId%22%3A%22me%22%2C%22includeSpamTrash%22%3Afalse%2C%22labelIds%22%3A%5B%22LM%22%5D%7D
    #*************************************

    response= service.users().messages().list(userId="me", labelIds=labelid, q=None, pageToken=None, maxResults=None, includeSpamTrash=None).execute()
    all_message_in_label = []
    if 'messages' in response:
        all_message_in_label.extend(response['messages'])

    while 'nextPageToken' in response:
      page_token = response['nextPageToken']
      response = service.users().messages().list(userId="me", labelIds=labelid, q=None, pageToken=page_token, maxResults=None, includeSpamTrash=None).execute()
      all_message_in_label.extend(response['messages'])


    # all_message_in_label looks like this 
            # for email in all_message_in_label:
                # print(email)
                #{'id': '169735e289ba7310', 'threadId': '169735e289ba7310'}
                #{'id': '169735c76a4b93af', 'threadId': '169735c76a4b93af'}    
    if not all_message_in_label:
        print('No email LM found.')
    else:
        # for each ID in all_message_in_label we *get* the message 

        #*************************************
        # ressources for *get* email 
        # https://developers.google.com/resources/api-libraries/documentation/gmail/v1/python/latest/gmail_v1.users.messages.html#get
        # code example for decode https://developers.google.com/gmail/api/v1/reference/users/messages/get 
        #  + decode for python 3 https://python-forum.io/Thread-TypeError-initial-value-must-be-str-or-None-not-bytes--12161
        #*************************************

        for emails in all_message_in_label: 
            message= service.users().messages().get(userId="me", id=emails["id"], format="raw", metadataHeaders=None).execute()
            msg_str = base64.urlsafe_b64decode(message['raw'].encode('ASCII'))

            try: 
                mime_msg = email.message_from_string(msg_str.decode())  

                # the the message as a .eml file 
                outfile_name = os.path.join(emailfolder, f'{emails["id"]}.eml')

                with open(outfile_name, 'w') as outfile:
                    gen = email.generator.Generator(outfile)
                    gen.flatten(mime_msg)
                print("mail saved: ", emails["id"])

            except:
                print("error in message ", message["snippet"])

if __name__ == '__main__':
    main()

这是第二个脚本“get labels ids.py”(cf“Set up”步骤4)。在第一个脚本中)

# source  = https://developers.google.com/gmail/api/quickstart/python?authuser=2

from __future__ import print_function
import pickle
import os.path
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 = ['https://www.googleapis.com/auth/gmail.readonly']


def main():
    creds = None
    if os.path.exists('token.pickle'):
        with open('token.pickle', 'rb') as token:
            creds = pickle.load(token)
    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()
        with open('token.pickle', 'wb') as token:
            pickle.dump(creds, token)

    service = build('gmail', 'v1', credentials=creds)

    # Get list of all labels
    #  https://developers.google.com/resources/api-libraries/documentation/gmail/v1/python/latest/index.html
    results = service.users().labels().list(userId='me').execute()
    labels = results.get('labels', [])

    if not labels:
        print('No labels found.')
    else:
        print('Labels:')
    for label in labels:
        print(label['name'] + " "+label['id'])


if __name__ == '__main__':
    main()
    input("continue")