J'ai essayé d'envoyer un e-mail d'Amazon SES avec Python

Déclencheur

Il est nécessaire d'envoyer régulièrement des e-mails à plusieurs destinataires dans l'entreprise, et jusqu'à présent, Gmail était envoyé de manière pacifique avec tableur + GAS. Mais! Les spécifications ont changé dans le système d'envoi de courrier interne! (Système de prévention de transmission d'erreur) En conséquence, la feuille de calcul + GAS Gmail ne fonctionne parfois pas: sanglot: Wow Gmail n'est pas bon, envoyez un autre e-mail ... OK, allons à Amazon SES!

Expérience d'envoi d'e-mails depuis Amazon SES avec Python

Tout d'abord, SES du Boto3 Official Document Vérifiez /latest/reference/services/ses.html). Hmmm, ce serait bien d'utiliser send_email (** kwargs) ou send_raw_email (** kwargs). La différence est que send_raw_email (** kwargs) vous permet de spécifier des en-têtes et de joindre des fichiers. Au contraire, send_email (** kwargs) ne correspond pas à ce côté, mais c'est simple. Je veux joindre un fichier, mais cette fois je veux l'implémenter rapidement pour que je puisse envoyer du courrier rapidement, alors allons-y avec send_email (** kwargs).

Tout d'abord, lisez ses avec Boto3

import boto3

client = boto3.client('ses', 
        aws_access_key_id = accesskey, 
        aws_secret_access_key = secretkey, 
        region_name = region
    )

Envoyer avec send_email (** kwargs)

client.send_email(
        Source = '[email protected]',
        Destination = {
            'ToAddresses': [
                '[email protected]',
            ]
        },
        Message = {
            'Subject': {
                'Data': 'E-mail test',
                'Charset': 'UTF-8'
            },
            'Body': {
                'Text': {
                    'Data': 'Corps de test',
                    'Charset': 'UTF-8'
                }
            }
        }
    )

Très bien, les bases sont OK. Ensuite, je vais le réécrire en quelque chose qui peut réellement être utilisé. Remarque: Amazon SES nouvellement créé a des fonctions limitées et vous devez enregistrer l'adresse e-mail à utiliser à l'avance. Pour plus d'informations, consultez la [Foire aux questions sur Amazon SES] officielle (https://aws.amazon.com/jp/ses/faqs/) Q: Qu'est-ce que Amazon SES Sandbox? S'il te plait donne moi.

Mise en œuvre de la production

J'ai confirmé qu'il peut être envoyé avec succès avec send_email (** kwargs), donc je vais l'implémenter afin qu'il puisse être utilisé en production. Tout d'abord, je ne veux pas intégrer les informations d'identification AWS dans le code, je l'ai donc lu à partir d'un fichier CSV (un fichier téléchargé depuis IAM).

import csv

def get_credentials():
    with open('Fichier CSV d'identification') as f:
        credentials_file = csv.reader(f)
        #Lisez la deuxième ligne car la première ligne du fichier CSV d'informations d'identification AWS est le nom de l'élément
        next(credentials_file)
        for credentials_array in credentials_file:
            return credentials_array

Ensuite, je pense que le contenu du courrier devrait être facile à mettre à jour, alors lisez-le à partir d'un fichier texte externe. Puisque je veux séparer le titre du courrier et le corps du courrier, je vais définir une cible appropriée dans le fichier texte comme ----- corps du courrier ----- à partir d'ici. Image du fichier de contenu de messagerie

Objet de l'e-mail de test
-----Corps de l'e-mail à partir d'ici-----
Testez le corps de l'e-mail.
def get_mail_content():
    with open('Fichier texte du contenu de l'e-mail') as f:
        mail_content_all = f.read()
    mail_content_splitted = mail_content_all.split('\n-----Corps de l'e-mail à partir d'ici-----\n')
    return mail_content_splitted

Assurez-vous que l'adresse e-mail du destinataire est également lue à partir du fichier CSV externe afin qu'elle puisse être facilement mise à jour.

def get_addresses():
    with open('Fichier CSV d'adresse e-mail') as f:
        addresses_file = csv.reader(f)
        for addresses_array in addresses_file:
            return addresses_array

Maintenant que vous avez toutes les informations dont vous avez besoin pour votre e-mail, collectez les informations dont vous avez besoin à partir de la fonction que vous avez créée et envoyez-les avec send_email (** kwargs).

#Obtenez les informations d'identification AWS
access_key = get_credentials()[0]
secret_key = get_credentials()[1]

client = boto3.client('ses',
    aws_access_key_id = access_key,
    aws_secret_access_key = secret_key,
    region_name = 'Région utilisée par Amazon SES (pas encore de Japon)'
)

#Obtenir le contenu des e-mails
mail_title = get_mail_content()[0]
mail_body = get_mail_content()[1]

#Obtenir une adresse e-mail
to_addresses = get_addresses()
#Puisque l'adresse e-mail doit être transmise dans un tableau[ ]Entourez de
cc_addresses = ['Adresse e-mail de destination CC']

#envoyer un e-mail
client.send_email(
    Source = 'Adresse e-mail de l'expéditeur',
    Destination = {
        'ToAddresses': to_addresses,
        'CcAddresses': cc_addresses
    },
    Message = {
        'Subject': {
            'Data': mail_title,
            'Charset': 'UTF-8'
        },
        'Body': {
            'Text': {
                'Data': mail_body,
                'Charset': 'UTF-8'
            }
        }
    }
)

C'est acceptable! J'ai pensé, mais la [Foire aux questions sur Amazon SES] officielle (https://aws.amazon.com/jp/ses/faqs/) a cette explication.

Q: Y a-t-il une limite au nombre de destinataires pouvant être spécifiés dans un seul e-mail?

Vous pouvez spécifier jusqu'à 50 destinataires pour chaque message que vous envoyez à l'aide d'Amazon SES. Toutes les adresses des champs «À:», «CC:» et «BCC:» sont incluses dans cette limite. Si vous souhaitez envoyer un e-mail à plus de 50 destinataires, vous devez diviser la liste des destinataires en groupes de 50 ou moins et envoyer les messages dans chaque groupe.

En passant, si vous dépassez 50 personnes, le message d'erreur suivant sera renvoyé.

botocore.exceptions.ClientError: An error occurred (InvalidParameterValue) when calling the SendEmail operation: Recipient count exceeds 50.

Prend en charge l'envoi de 50 personnes

Je vois. Il est nécessaire de traiter le nombre de destinataires à envoyer à la fois à 50 ou moins. Tout d'abord, faites de la partie d'envoi de courrier une fonction.

def send_email(client, to_addresses, cc_addresses, mail_title, mail_body):
    #Processus d'envoi d'e-mails
    client.send_email(
        Source = 'Adresse e-mail de l'expéditeur',
        Destination = {
            'ToAddresses': to_addresses,
            'CcAddresses': cc_addresses
        },
        Message = {
            'Subject': {
                'Data': mail_title,
                'Charset': 'UTF-8'
            },
            'Body': {
                'Text': {
                    'Data': mail_body,
                    'Charset': 'UTF-8'
                }
            }
        }
    )

Si vous appelez ce send_email pour 50 destinataires

cc_addresses = ['Adresse e-mail de destination CC']
to_addresses = get_addresses()
to_addresses_splitted = []
#Bouclez le nombre d'ensembles tous les 50_Attribuer pour compter
loop_count = len(to_addresses) // 50 + 1
for i in range(loop_count):
    #Obtenez 50 éléments (y compris l'adresse e-mail CC) dans l'ensemble un par un
    for j in range(50 - len(cc_addresses)):
        # send_À de la liste des adresses e-mail à transmettre à l'e-mail_addresses_Entrez l'adresse e-mail dans l'ordre divisé
        try:
            to_addresses_splitted.append(to_addresses[i * 50 + j])
        #Gestion des exceptions lorsqu'un index inexistant est spécifié
        except:
            pass
    send_email(client, to_addresses_splitted, cc_addresses, mail_title, mail_body)
    #Effacer chaque ensemble
    to_addresses_splitted = []

Oups, tous les e-mails fractionnés seront envoyés à l'adresse e-mail CC. Je ne veux pas envoyer un e-mail à l'adresse e-mail CC à la fois, je l'enverrai donc à l'adresse e-mail CC uniquement pour la première transmission fractionnée.

def send_email(client, to_addresses, cc_addresses, mail_title, mail_body, i):
    #Envoyer à l'adresse CC uniquement pour le premier fractionnement
    if 0 == i:
        destination_value = {
            'ToAddresses': to_addresses,
            'CcAddresses': cc_addresses
        }
    else:
        destination_value = {
            'ToAddresses': to_addresses
        }

    #Processus d'envoi d'e-mails
    client.send_email(
        Source = 'Adresse e-mail de l'expéditeur',
        Destination = destination_value,
        Message = {
            'Subject': {
                'Data': mail_title,
                'Charset': 'UTF-8'
            },
            'Body': {
                'Text': {
                    'Data': mail_body,
                    'Charset': 'UTF-8'
                }
            }
        }
    )

Résumé

import boto3
import csv

def main():
    #Informations AWS
    access_key = get_credentials()[0]
    secret_key = get_credentials()[1]

    client = boto3.client('ses',
        aws_access_key_id = access_key,
        aws_secret_access_key = secret_key,
        region_name = 'us-east-1'
    )

    #Obtenir le contenu des e-mails
    mail_title = get_mail_content()[0]
    mail_body = get_mail_content()[1]

    #Obtenir une adresse e-mail
    cc_addresses = ['Adresse e-mail de destination CC']
    to_addresses = get_addresses()
    to_addresses_splitted = []
    #Bouclez le nombre d'ensembles tous les 50_Attribuer pour compter
    loop_count = len(to_addresses) // 50 + 1
    for i in range(loop_count):
        #Obtenez 50 articles (y compris l'adresse e-mail CC) dans l'ensemble un par un
        for j in range(50 - len(cc_addresses)):
            # send_À de la liste des adresses e-mail à transmettre à l'e-mail_addresses_Entrez l'adresse e-mail dans l'ordre divisé
            try:
                to_addresses_splitted.append(to_addresses[i * 50 + j])
            #Gestion des exceptions lorsqu'un index inexistant est spécifié
            except:
                pass
        send_email(client, to_addresses_splitted, cc_addresses, mail_title, mail_body, i)
        #Effacer chaque ensemble
        to_addresses_splitted = []

def get_credentials():
    with open('credentials.csv') as f:
        credentials_file = csv.reader(f)
        #Lisez la deuxième ligne car la première ligne du fichier CSV d'informations d'identification AWS est le nom de l'élément
        next(credentials_file)
        for credentials_array in credentials_file:
            return credentials_array

def get_addresses():
    with open('addresses.csv') as f:
        addresses_file = csv.reader(f)
        for addresses_array in addresses_file:
            return addresses_array

def get_mail_content():
    with open('mail_content.txt') as f:
        mail_content_all = f.read()
    mail_content_splitted = mail_content_all.split('\n---------------------Corps de l'e-mail à partir d'ici---------------------\n')
    return mail_content_splitted

def send_email(client, to_addresses, cc_addresses, mail_title, mail_body, i):
    #Envoyer à l'adresse CC uniquement pour le premier fractionnement
    if 0 == i:
        destination_value = {
            'ToAddresses': to_addresses,
            'CcAddresses': cc_addresses
        }
    else:
        destination_value = {
            'ToAddresses': to_addresses
        }

    #Processus d'envoi d'e-mails
    client.send_email(
        Source = 'Adresse e-mail de l'expéditeur',
        Destination = destination_value,
        Message = {
            'Subject': {
                'Data': mail_title,
                'Charset': 'UTF-8'
            },
            'Body': {
                'Text': {
                    'Data': mail_body,
                    'Charset': 'UTF-8'
                }
            }
        }
    )

if __name__ == "__main__":
    main()

Vous pouvez désormais envoyer des e-mails localement sans souci. Cependant, s'il provient du local, d'autres personnes ne peuvent pas l'envoyer (= je serai en charge de l'envoi du courrier), donc je me demande si ce sera AWS Lambda bientôt.

We're hiring! Nous développons un chatbot IA. Si vous êtes intéressé, n'hésitez pas à nous contacter depuis la page Wantedly!

Article de référence

Documentation officielle Boto3 Questions fréquentes sur Amazon SES

Recommended Posts

J'ai essayé d'envoyer un e-mail d'Amazon SES avec Python
J'ai essayé d'envoyer un email avec SendGrid + Python
Envoyer un e-mail avec Amazon SES + Python
J'ai essayé d'envoyer du courrier depuis le serveur Sakura avec flask-mail
J'ai essayé d'envoyer un SMS avec Twilio
J'ai essayé fp-growth avec python
J'ai essayé de gratter avec Python
J'ai essayé gRPC avec Python
J'ai essayé de gratter avec du python
J'ai essayé d'implémenter le perceptron artificiel avec python
J'ai essayé d'utiliser la bibliothèque Python de Ruby avec PyCall
[Python] Envoyez un e-mail depuis Gmail avec le paramètre d'authentification en deux étapes
J'ai essayé webScraping avec python.
J'ai envoyé un SMS avec Python
Transmission de courrier facile avec Hâte Python3
J'ai essayé d'exécuter prolog avec python 3.8.2.
[Python] Envoyez des e-mails avec Outlook
J'ai essayé la communication SMTP avec Python
J'ai essayé de créer une fonction de similitude d'image avec Python + OpenCV
J'ai essayé d'utiliser Amazon SQS avec django-celery
J'ai essayé le rendu non réaliste avec Python + opencv
J'ai essayé d'utiliser l'API UnityCloudBuild de Python
J'ai essayé un langage fonctionnel avec Python
J'ai essayé la récurrence avec Python ② (séquence de nombres Fibonatch)
Scraping depuis un site authentifié avec python
# J'ai essayé quelque chose comme Vlookup avec Python # 2
[Bases de la science des données] J'ai essayé d'enregistrer de csv à mysql avec python
J'ai essayé d'envoyer un e-mail de fin d'inscription depuis Gmail avec django.
[Outlook] J'ai essayé de créer automatiquement un e-mail de rapport quotidien avec Python
J'ai essayé des centaines de millions de SQLite avec python
J'ai essayé de "différencier" l'image avec Python + OpenCV
Envoyez un email à l'adresse de Spushi avec python
Je souhaite envoyer un e-mail depuis Gmail en utilisant Python.
J'ai essayé Python! ] Diplômé aujourd'hui de "Tout le monde Python! Qu'est-ce que Python!"!
J'ai essayé L-Chika avec Razpai 4 (édition Python)
J'ai essayé la différenciation jacobienne et partielle avec python
J'ai essayé d'obtenir des données CloudWatch avec Python
J'ai essayé d'utiliser mecab avec python2.7, ruby2.3, php7
J'ai essayé la synthèse de fonctions et le curry avec python
J'ai essayé de sortir LLVM IR avec Python
J'ai essayé de "binariser" l'image avec Python + OpenCV
Générez une instruction d'insertion à partir de CSV avec Python.
J'ai essayé d'exécuter faiss avec python, Go, Rust
J'ai essayé de détecter un objet avec M2Det!
J'ai essayé d'automatiser la fabrication des sushis avec python
J'ai essayé d'exécuter Deep Floor Plan avec Python 3.6.10.
J'ai essayé de démarrer Jupyter avec toutes les lumières d'Amazon
Envoyer un e-mail avec Excel en pièce jointe en Python
J'ai fait une application d'envoi de courrier simple avec tkinter de Python
J'ai essayé d'extraire le dessin au trait de l'image avec Deep Learning
[Python] J'ai essayé le même calcul que la prédiction de LSTM à partir de zéro [Keras]
J'ai essayé Python> autopep8
Valider l'e-mail avec Python
Envoyer des e-mails par Python
J'ai essayé Python> décorateur
J'ai essayé d'implémenter Mine Sweeper sur un terminal avec python
J'ai fait une analyse émotionnelle d'Amazon Comprehend avec l'AWS CLI.