web-dev-qa-db-fra.com

Comment envoyer du texte HTML et une pièce jointe à l'aide de boto3 send_email ou send_raw_email?

Comment envoyer une pièce jointe en utilisant boto SES send_email client?

Je sais que je peux utiliser send_raw_email pour envoyer une pièce jointe mais je dois envoyer le corps du message avec html data. Si ce n'est pas possible, comment envoyer un email avec des données html en utilisant boto3.ses.send_raw_email ()?

11
DKo

Exemple de copie sans vergogne de " COMMENT ENVOYER DES MAILS HTML EN UTILISANT Amazon SES " Voici à quoi ressemble un contenu de données de messagerie typique.

 message_dict = { 'Data':
  'From: ' + mail_sender + '\n'
  'To: ' + mail_receivers_list + '\n'
  'Subject: ' + mail_subject + '\n'
  'MIME-Version: 1.0\n'
  'Content-Type: text/html;\n\n' +
  mail_content}

Si vous souhaitez envoyer une pièce jointe et du texte HTML à l'aide de boto3.ses.send_raw_email , il vous suffit d'utiliser le message ci-dessus dict et pass. (mettez simplement votre texte html sous le mail_content)

response = client.send_raw_email(
    Destinations=[
    ],
    FromArn='',
    RawMessage=message_dict,
    ReturnPathArn='',
    Source='',
    SourceArn='',
)

En fait, l'en-tête brut des pièces jointes devrait fonctionner à la fois dans send_email () et send_raw_email (). Sauf dans send_mail, vous devez placer la pièce jointe dans Text, pas html.

4
mootmoot

Après avoir parcouru plusieurs sources, y compris d'autres SO questions, blogs et Python, j'ai trouvé le code ci-dessous).

Permet les e-mails et les pièces jointes en texte et/ou en HTML.

Séparez les parties MIME et boto3, au cas où vous souhaiteriez réutiliser MIME à d'autres fins, comme envoyer un e-mail avec un client SMTP, au lieu de boto3.

import os
import boto3
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication


def create_multipart_message(
        sender: str, recipients: list, title: str, text: str=None, html: str=None, attachments: list=None)\
        -> MIMEMultipart:
    """
    Creates a MIME multipart message object.
    Uses only the Python `email` standard library.
    Emails, both sender and recipients, can be just the email string or have the format 'The Name <[email protected]>'.

    :param sender: The sender.
    :param recipients: List of recipients. Needs to be a list, even if only one recipient.
    :param title: The title of the email.
    :param text: The text version of the email body (optional).
    :param html: The html version of the email body (optional).
    :param attachments: List of files to attach in the email.
    :return: A `MIMEMultipart` to be used to send the email.
    """
    multipart_content_subtype = 'alternative' if text and html else 'mixed'
    msg = MIMEMultipart(multipart_content_subtype)
    msg['Subject'] = title
    msg['From'] = sender
    msg['To'] = ', '.join(recipients)

    # Record the MIME types of both parts - text/plain and text/html.
    # According to RFC 2046, the last part of a multipart message, in this case the HTML message, is best and preferred.
    if text:
        part = MIMEText(text, 'plain')
        msg.attach(part)
    if html:
        part = MIMEText(html, 'html')
        msg.attach(part)

    # Add attachments
    for attachment in attachments or []:
        with open(attachment, 'rb') as f:
            part = MIMEApplication(f.read())
            part.add_header('Content-Disposition', 'attachment', filename=os.path.basename(attachment))
            msg.attach(part)

    return msg


def send_mail(
        sender: str, recipients: list, title: str, text: str=None, html: str=None, attachments: list=None) -> dict:
    """
    Send email to recipients. Sends one mail to all recipients.
    The sender needs to be a verified email in SES.
    """
    msg = create_multipart_message(sender, recipients, title, text, html, attachments)
    ses_client = boto3.client('ses')  # Use your settings here
    return ses_client.send_raw_email(
        Source=sender,
        Destinations=recipients,
        RawMessage={'Data': msg.as_string()}
    )


if __name__ == '__main__':
    sender_ = 'The Sender <[email protected]>'
    recipients_ = ['Recipient One <[email protected]>', '[email protected]']
    title_ = 'Email title here'
    text_ = 'The text version\nwith multiple lines.'
    body_ = """<html><head></head><body><h1>A header 1</h1><br>Some text."""
    attachments_ = ['/path/to/file1/filename1.txt', '/path/to/file2/filename2.txt']

    response_ = send_mail(sender_, recipients_, title_, text_, body_, attachments_)
    print(response_)
13
Joao Coelho

Cela a fonctionné pour moi d'envoyer une pièce jointe:

from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

import boto.ses


AWS_ACCESS_KEY = 'HEREYOURACCESSKEY'
AWS_SECRET_KEY = 'HEREYOURSECRETKEY'

class Email(object):

    def __init__(self, to, subject):
        self.to = to
        self.subject = subject
        self.text = None
        self.attachment = None


    def text(self, text):
        self.text = text

    def add_attachment(self, attachment):
        self.attachment = attachment

    def send(self, from_addr=None, file_name = None):

        connection = boto.ses.connect_to_region(
            'us-east-1',
            aws_access_key_id=AWS_ACCESS_KEY,
            aws_secret_access_key=AWS_SECRET_KEY
        )
        msg = MIMEMultipart()
        msg['Subject'] = self.subject
        msg['From'] = from_addr
        msg['To'] = self.to

        part = MIMEApplication(self.attachment)
        part.add_header('Content-Disposition', 'attachment', filename=file_name)
        part.add_header('Content-Type', 'application/vnd.ms-Excel; charset=UTF-8')

        msg.attach(part)

        # the message body
        part = MIMEText(self.text)
        msg.attach(part)

        return connection.send_raw_email(msg.as_string(),source=from_addr,destinations=self.to)

if __name__ == "__main__":
    email = Email(to='[email protected]', subject='Your subject!')
    email.text('This is a text body.')
    #you could use StringIO.StringIO() to get the file value
    email.add_attachment(yourFileValue)
    email.send(from_addr='[email protected]',file_name="yourFile.txt")
3
Ezequiel Salas

Pour développer la réponse de @ adkl, le propre exemple d'Amazon utilise une ancienne méthode Python de gestion des e-mails et des pièces jointes. Rien de mal à cela, juste que la documentation actuelle sur ces modules n'est pas complète et peut être source de confusion pour de nouveaux utilisateurs comme moi.

Voici un exemple simple sur la formation d'un message avec une pièce jointe CSV.

from email.message import EmailMessage


def create_email_message(sender: str, recipients: list, title: str, text: str,
                         attachment: BytesIO, file_name: str) -> EmailMessage:
    msg = EmailMessage()
    msg["Subject"] = title
    msg['From'] = sender
    msg['To'] = ', '.join(recipients)
    msg.set_content(text)
    data = attachment.read()
    msg.add_attachment(
        data,
        maintype="text",
        subtype="csv",
        filename=file_name
    )
    return msg

# Client init, attachment file creation here

message = create_email_message(...)
try:
    ses.send_raw_email(
        Source=sender,
        Destinations=recipients,
        RawMessage={'Data': message.as_string()}
    )
except ClientError as e:
    logger.exception(f"Cannot send email report to {recipients}: {e}")
else:
    logger.info("Sent report successfully")

Dans cet exemple, j'utilise BytesIO objet comme source de pièce jointe, mais vous pouvez utiliser n'importe quel objet de type fichier qui prend en charge la méthode read().

3
Oleksii Donoha

mars 2019

Voici une solution copiée-collée de la documentation officielle [~ # ~] mise à jour [~ # ~] ( https://docs.aws.Amazon.com/ses/ dernier/DeveloperGuide/send-email-raw.html ):

import os
import boto3
from botocore.exceptions import ClientError
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication

# Replace [email protected] with your "From" address.
# This address must be verified with Amazon SES.
SENDER = "Sender Name <[email protected]>"

# Replace [email protected] with a "To" address. If your account 
# is still in the sandbox, this address must be verified.
RECIPIENT = "[email protected]"

# Specify a configuration set. If you do not want to use a configuration
# set, comment the following variable, and the 
# ConfigurationSetName=CONFIGURATION_SET argument below.
CONFIGURATION_SET = "ConfigSet"

# If necessary, replace us-west-2 with the AWS Region you're using for Amazon SES.
AWS_REGION = "us-west-2"

# The subject line for the email.
SUBJECT = "Customer service contact info"

# The full path to the file that will be attached to the email.
ATTACHMENT = "path/to/customers-to-contact.xlsx"

# The email body for recipients with non-HTML email clients.
BODY_TEXT = "Hello,\r\nPlease see the attached file for a list of customers to contact."

# The HTML body of the email.
BODY_HTML = """\
<html>
<head></head>
<body>
<h1>Hello!</h1>
<p>Please see the attached file for a list of customers to contact.</p>
</body>
</html>
"""

# The character encoding for the email.
CHARSET = "utf-8"

# Create a new SES resource and specify a region.
client = boto3.client('ses',region_name=AWS_REGION)

# Create a multipart/mixed parent container.
msg = MIMEMultipart('mixed')
# Add subject, from and to lines.
msg['Subject'] = SUBJECT 
msg['From'] = SENDER 
msg['To'] = RECIPIENT

# Create a multipart/alternative child container.
msg_body = MIMEMultipart('alternative')

# Encode the text and HTML content and set the character encoding. This step is
# necessary if you're sending a message with characters outside the ASCII range.
textpart = MIMEText(BODY_TEXT.encode(CHARSET), 'plain', CHARSET)
htmlpart = MIMEText(BODY_HTML.encode(CHARSET), 'html', CHARSET)

# Add the text and HTML parts to the child container.
msg_body.attach(textpart)
msg_body.attach(htmlpart)

# Define the attachment part and encode it using MIMEApplication.
att = MIMEApplication(open(ATTACHMENT, 'rb').read())

# Add a header to tell the email client to treat this part as an attachment,
# and to give the attachment a name.
att.add_header('Content-Disposition','attachment',filename=os.path.basename(ATTACHMENT))

# Attach the multipart/alternative child container to the multipart/mixed
# parent container.
msg.attach(msg_body)

# Add the attachment to the parent container.
msg.attach(att)
#print(msg)
try:
    #Provide the contents of the email.
    response = client.send_raw_email(
        Source=SENDER,
        Destinations=[
            RECIPIENT
        ],
        RawMessage={
            'Data':msg.as_string(),
        },
        ConfigurationSetName=CONFIGURATION_SET
    )
# Display an error if something goes wrong. 
except ClientError as e:
    print(e.response['Error']['Message'])
else:
    print("Email sent! Message ID:"),
    print(response['MessageId'])
2
adkl

Cela peut également être implémenté en utilisant python version 2.7.x

Voici le code de travail pour this--

[Remarque - L '"expéditeur" et les "destinataires" que vous ajoutez doivent être vérifiés dans AWS SES. OR SES doit être déplacé de l'état 'sandbox' à l'état 'Production'

import os
import boto3
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication


def create_multipart_message(email_metadata):        
    sender = email_metadata['sender_']
    recipients = email_metadata['recipients_']
    title = email_metadata['title_']
    text = email_metadata['text_']
    html = email_metadata['body_']
    attachments = email_metadata['attachments_']

    multipart_content_subtype = 'alternative' if text and html else 'mixed'
    msg = MIMEMultipart(multipart_content_subtype)
    msg['Subject'] = title
    msg['From'] = sender
    msg['To'] = ', '.join(recipients)

    # Record the MIME types of both parts - text/plain and text/html.
    # According to RFC 2046, the last part of a multipart message, in this case the HTML message, is best and preferred.
    if text:
        part = MIMEText(text, 'plain')
        msg.attach(part)
    if html:
        part = MIMEText(html, 'html')
        msg.attach(part)

    # Add attachments
    for attachment in attachments or []:
        with open(attachment, 'rb') as f:
            part = MIMEApplication(f.read())
            part.add_header('Content-Disposition', 'attachment', filename=os.path.basename(attachment))
            msg.attach(part)

    return msg


def send_mail(email_metadata):
        #sender: str, recipients: list, title: str, text: str=None, html: str=None, attachments: list=None) -> dict:
    """
    Send email to recipients. Sends one mail to all recipients.
    The sender needs to be a verified email in SES.
    """
    msg = create_multipart_message(email_metadata)
    ses_client = boto3.client('ses')  # Use your settings here
    return ses_client.send_raw_email(
        Source=email_metadata['sender_'],
        Destinations=email_metadata['recipients_'],
        RawMessage={'Data': msg.as_string()}
    )


if __name__ == '__main__':
    email_metadata = {
    "sender_" : "The Sender <[email protected]>",
    "recipients_" : ['Recipient One <[email protected]>','Recipient two <[email protected]>'],
    "title_" : "Email title here",
    "text_" : "The text version\nwith multiple lines.",
    "body_" : "<html><head></head><body><h1>A header 1</h1><br>Some text.",
    "attachments_" : ['/path/to/file1/filename1.txt','/path/to/file2/filename2.txt']
    }

    response_ = send_mail(email_metadata)
    print(response_)
0
Aayush Dalvi

Voici le cours que j'ai fini par utiliser. Déposez-le dans un fichier Lambda et utilisez-le.

Accepte une liste de noms de fichiers pour les pièces jointes. Envoie HTML e-mail. Changements \n pour <br />

J'ai enregistré la classe ci-dessous [1] en tant que emailer.py et utiliser comme:

from emailer import Emailer

def lambda_handler(event, context):
  # ...
  emailer = Emailer()
  emailer.send(
    to=email_recipients_list, 
    subject=subject_string, 
    fromx=from_address_string, 
    body=email_body_string, 
    attachments=attachments_list
  )

[1]

import boto3
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart


class Emailer(object):
    """ send email with attachments """

    def send(self, to, subject, fromx, body=None, content=None, attachments=[]):
        """ sends email with attachments

        Parameters:
            * to (list or comma separated string of addresses): recipient(s) address
            * fromx (string): from address of email
            * body (string, optional): Body of email ('\n' are converted to '< br/>')
            * content (string, optional): Body of email specified as filename
            * attachments (list, optional): list of paths of files to attach
        """

        self.to = to
        self.subject = subject
        self.fromx = fromx
        self.attachment = None
        self.body = body
        self.content = content
        self.attachments = attachments

        if type(self.to) is list:
            self.to = ",".join(self.to)


        message = MIMEMultipart()

        message['Subject'] = self.subject
        message['From'] = self.fromx
        message['To'] = self.to
        if self.content and os.path.isfile(self.content):
            part = MIMEText(open(str(self.content)).read().replace("\n", "<br />"), "html")
            message.attach(part)
        Elif self.body:
            part = MIMEText(self.body.replace("\\n", "<br />").replace("\n", "<br />"), "html")
            message.attach(part)


        for attachment in self.attachments:
            part = MIMEApplication(open(attachment, 'rb').read())
            part.add_header('Content-Disposition', 'attachment', filename=attachment.split("/")[-1])
            message.attach(part)

        ses = boto3.client('ses', region_name='us-east-1')

        response = ses.send_raw_email(
            Source=message['From'],
            Destinations=message['To'].split(","),
            RawMessage={
                'Data': message.as_string()
            }
        )
0
arod