Je souhaite télécharger plus de 100 e-mails de gmail au format pdf. Il serait trop long de tous les télécharger manuellement via l'option d'impression dans gmail.

Ce script python récupère les e-mails dans l'étiquette choisie. Comment puis-je convertir cet e-mail en pdf.

# 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



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 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)

    # Call the Gmail API 

    response= service.users().messages().list(userId="me", labelIds="Label_53", 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="Label_53", q=None, pageToken=page_token, maxResults=None, includeSpamTrash=None).execute()
      all_message_in_label.extend(response['messages'])


    if not all_message_in_label:
        print('No email LM found.')
    else:
        # get message from Id listed in all_message_in_label
        for emails in all_message_in_label: 
            message= service.users().messages().get(userId="me", id=emails["id"], format="raw", metadataHeaders=None).execute()



if __name__ == '__main__':
    main()
3
MagTun 12 mars 2019 à 23:44

2 réponses

Meilleure réponse

J'ai creusé un peu votre problème et j'ai trouvé quelques liens qui pourraient être utiles:

Sur la conversion de vos messages au format .eml ce lien.

Sur la conversion de .eml en .pdf ces liens :

eml2pdf est un projet python github qui convertit les fichiers eml en pdf mais je je ne sais pas si ça marche ou pas. Vous pouvez vérifier pour voir si cela fonctionne.

eml-to-pdf est un autre projet github qui semble inférieur mais qui fonctionne. c'est écrit en javascript.

Et il existe pyPdf que vous pouvez utiliser pour générer des fichiers pdf. mais avec cela, vous devrez peut-être convertir les e-mails et les formater vous-même.

Pour plus d'informations sur la mise en forme des objets de message, vous pouvez vous référer à la documentation gmail api python get.

Et voici un article de blog qui fait ce que vous cherchez pour avoir utilisé une approche différente bien que je ne sois pas tout à fait sûr que cela fonctionne toujours.

J'espère que ça aide. Bonne chance.

1
Ali Nuri Şeker 12 mars 2019 à 22:12

J'ai essayé les recommandations de la réponse d'Ali Nuri Seker mais elles n'ont pas fonctionné :
- eml2pdf : ne fonctionne pas sous Windows
- eml-to-pdf : erreur dans le type Mime
- pyPdf : trop de travail car vous devez construire l'ensemble du design - gmail-to-pdf : bug dans le code de certains emails (cf le bug est mentionné sur github)

Ce qui a fonctionné (même idée générale qu'Ali Nuri Seker) :

  1. enregistrez les e-mails au format .eml avec email.generator.Generator
  2. Utilisez eml-to-pdf-converter (non basé sur python mais open source GUI ) pour convertir le fichier .eml en pdf (il vous suffit de déposer le dossier contenant vos fichiers .eml, de cliquer sur un bouton et vous obtenez votre pdf. Cela fonctionne même avec les sous-dossiers !)

Des scripts plus détaillés peuvent être trouvés ici


Ceci est le premier script "enregistrer l'e-mail en tant que .eml":

# 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()

C'est le deuxième script "get labels ids.py" (cf "Set up" étape 4. dans le premier script)

# 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")
2
MagTun 28 mars 2019 à 16:03