web-dev-qa-db-fra.com

Comment envoyer des emails au format HTML via gmail-api pour python

Utilisation de l'exemple de code de l'API GMail Exemple: Send Mail , et après avoir suivi les règles d'authentification, il est assez simple d'envoyer un e-mail généré par programme, via un compte gmail. Ce qui n’est pas évident dans cet exemple, c’est la manière de définir le format HTML de cet e-mail.


La question

Comment obtenir le formatage HTML dans mes messages d'envoi gmail-api en utilisant python?

J'ai ceci...

message_body = "Hello!\nYou've just received a test message!\n\nSincerely,\n-Test Message Generator\n"

et je veux que ce soit ça ...

Hello!
You've just received a test message!

Sincerely,
-Test Message Generator

Exemple de code source de GMail-API

Vous trouverez ci-dessous une version légèrement modifiée de l'exemple, mais qui fonctionne toujours:

import argparse
import base64
from pprint import pformat
from pprint import pprint
import httplib2
import os
from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText

from apiclient import discovery
from oauth2client import client
from oauth2client import tools
from oauth2client.file import Storage


SCOPES = 'https://mail.google.com/'
CLIENT_SECRET_FILE = 'client_secret.json'
APPLICATION_NAME = 'Test EMail App'


def get_credentials():
    """Gets valid user credentials from storage.

    If nothing has been stored, or if the stored credentials are invalid,
    the OAuth2 flow is completed to obtain the new credentials.

    Returns:
        Credentials, the obtained credential.
    """

    home_dir = os.path.expanduser('~')
    credential_dir = os.path.join(home_dir, '.credentials')
    if not os.path.exists(credential_dir):
        os.makedirs(credential_dir)
    credential_path = os.path.join(credential_dir,
                                   'gmail-python-quickstart.json')

    store = Storage(credential_path)
    credentials = store.get()
    if not credentials or credentials.invalid:
        flow = client.flow_from_clientsecrets(CLIENT_SECRET_FILE, SCOPES)
        flow.user_agent = APPLICATION_NAME
        if flags:
            credentials = tools.run_flow(flow, store, flags)
        else: # Needed only for compatibility with Python 2.6
            credentials = tools.run(flow, store)
        print('Storing credentials to ' + credential_path)
    return credentials

def create_message(sender, to, cc, subject, message_text):
    """Create a message for an email.

    Args:
    sender: Email address of the sender.
    to: Email address of the receiver.
    subject: The subject of the email message.
    message_text: The text of the email message.

    Returns:
    An object containing a base64url encoded email object.
    """
    print(sender + ', ' + to + ', ' + subject + ', ' + message_text)
    message = MIMEText(message_text)
    message['to'] = to
    message['from'] = sender
    message['subject'] = subject
    message['cc'] = cc
    pprint(message)
    return {'raw': base64.urlsafe_b64encode(message.as_string())}

def send_message(service, user_id, message_in):
    """Send an email message.

    Args:
    service: Authorized Gmail API service instance.
    user_id: User's email address. The special value "me"
    can be used to indicate the authenticated user.
    message: Message to be sent.

    Returns:
    Sent Message.
    """
    pprint(message_in)
    try:
        message = (service.users().messages().send(userId=user_id, body=message_in).execute())
        pprint(message)
        print ('Message Id: %s' % message['id'])
        return message
    except errors.HttpError, error:
        print ('An error occurred: %s' % error)

def main(cli):
    """Shows basic usage of the Gmail API.

    Creates a Gmail API service object and outputs a list of label names
    of the user's Gmail account.
    """


    credentials = get_credentials()
    http = credentials.authorize(httplib2.Http())
    service = discovery.build('gmail', 'v1', http=http)

    email_msg = create_message(cli.addr_from, cli.addr_to, cli.addr_cc, cli.subject, cli.message)
    msg_out = service.users().messages().send(userId = 'me', body = email_msg).execute()
    pprint(msg_out)


if __== '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('-m', '--message',   help = 'The message to send in the email', default='<MESSAGE = unfinished>')
    parser.add_argument('-t', '--addr_to',   help = 'the list of comma separated emails to send', default='[email protected]')
    parser.add_argument('-s', '--subject',   help = 'the email subject', default='<SUBJECT = undefined>')
    parser.add_argument('-c', '--addr_cc',   help = 'email CC\'s', default='')
    parser.add_argument('-f', '--addr_from', help = 'Email address to send from', default='[email protected]')
    cli = parser.parse_args()
    pprint(dir(cli))

    main(cli)

Même si j'ai essayé, avec ce code et ses variantes, je ne pouvais pas obtenir de code au format HTML, ni de simples caractères d'échappement pour créer des retours à la ligne là où ils devaient être.


Voici ce qui n'a pas fonctionné

Essayer ce qui suit n'a pas fonctionné non plus:

  1. modifier line 69 pour ajouter des paramètres supplémentaires au dictionnaire de messages ... c'est-à-dire
    • {'raw': base64.urlsafe_b64encode(message.as_string()), 'payload': {'mimeType': 'text/html'}}
    • Comme documenté ici dans GMail API Docs
    • enter image description here
  2. Ajout d'une variété de barres obliques inverses au texte du message:
    • \n... c'est-à-dire: \\n ni \\\n et juste restitué avec ces caractères exacts
    • L'ajout de <br> </br> <br/> n'a pas ajouté de nouvelles lignes et vient d'être restitué avec les mêmes caractères
    • L'ajout de \r n'ajoute pas de nouvelles lignes et vient d'être restitué avec le caractère exact

Raisons pour lesquelles il ne s'agit pas d'une question en double

16
Andrew

Après avoir beaucoup fouillé, j'ai commencé à examiner le côté python de la gestion des messages et ai constaté qu'un objet python est en train de construire le message à envoyer pour l'encodage en base64 dans le constructeur d'objet de message gmail-api.

Voir la ligne 63 ci-dessus: message = MIMEText(message_text)

La seule astuce qui a finalement fonctionné pour moi, après toutes les tentatives de modification des valeurs d'en-tête et de payload dict (membre de l'objet message), consistait à définir (line 63):

  • message = MIMEText(message_text, 'html') <- ajoute le 'html' comme second paramètre du constructeur d'objet MIMEText

Le code par défaut fourni par Google pour son API gmail vous indique uniquement comment envoyer des e-mails en texte brut, mais il cache comment il le fait . Ala ...message = MIMEText(message_text)

Je devais rechercher la classe python email.mime.text.MIMEText object. C'est là que vous verrez cette définition du constructeur pour l'objet MIMEText:

  • classe email.mime.text.MIMEText (_text [ _subtype [ _charset]]) Nous voulons lui transmettre explicitement une valeur pour le _subtype. Dans ce cas, nous voulons passer: 'html' en tant que _subtype.

Maintenant, vous n'aurez plus d'encapsulation Word inattendue appliquée à vos messages par Google, ni à l'objet Python mime.text.MIMEText


Le code fixe

 def create_message (expéditeur, à, cc, sujet, message_text): 
 "" "Créer un message pour un email .

 Args: 
 Expéditeur: Adresse email de l'expéditeur ..
 À: Adresse email du destinataire .
 Sujet: Objet de l'email message .
 message_text: Le texte de l'e-mail message .

 Renvoie: 
 Un objet contenant un objet email encodé en base64url .
 "" "
 print (expéditeur + ',' + à + ',' + sujet + ',' + message_text) 
 message = MIMEText (message_text, 'html') 
 message ['to'] = to 
 message ['de'] = expéditeur 
 message ['subject'] = subject 
 message ['cc'] = cc 
 pprint (message) 
 return {'raw': base64.urlsafe_b64encode (message.as_string ())} 
17
Andrew

Essaye ça:

    def CreateMessage(emailSubject, emailTo, emailFrom, message_body, emailCc, html_content=None):
        try:
            message = MIMEMultipart('alternative')
            message['to'] = emailTo
            message['from'] = emailFrom
            message['subject'] = emailSubject
            message['Cc'] = emailCc
            body_mime = MIMEText(message_body, 'plain')
            message.attach(body_mime)
            if html_content:
                html_mime = MIMEText(html_content, 'html')
                message.attach(html_mime)
            return {
                'raw': base64.urlsafe_b64encode(
                    bytes(
                        message.as_string(),
                        "utf-8")).decode("utf-8")}
        except Exception as e:
            print('Error in CreateMessage()', e)
            return '400'
1
Januka samaranyake