Fermer

novembre 13, 2018

Envoi d'emails de manière asynchrone via AWS SES


À propos de l'auteur

Leonardo Losoviz est le créateur de PoP un framework pour la construction de sites Web modulaires basés sur PHP et les guidons, et optimisé par WordPress. Il habite à Kuala…
Pour en savoir plus sur Leonardo

L'envoi simultané de plusieurs courriels transactionnels, s'il n'est pas correctement structuré, pourrait devenir un goulot d'étranglement pour l'application et nuire à l'expérience utilisateur. Une partie du problème est liée à la connexion synchrone au serveur SMTP depuis l’application. Dans cet article, nous verrons comment envoyer des courriers électroniques de l'extérieur de l'application, de manière asynchrone, en combinant AWS S3, Lambda et SES.

La plupart des applications envoient des courriels pour communiquer avec leurs utilisateurs. Les e-mails transactionnels sont ceux qui sont déclenchés par l’interaction de l’utilisateur avec l’application, par exemple lors de l’accueil d’un nouvel utilisateur après son inscription sur le site, la création d’un lien permettant à l’utilisateur de réinitialiser le mot de passe ou l’attachement d’une facture après que l’utilisateur a effectué un achat. Tous ces cas précédents nécessiteront généralement l'envoi d'un seul courrier électronique à l'utilisateur. Dans d’autres cas, cependant, l’application doit envoyer beaucoup plus de courriels, par exemple lorsqu'un utilisateur publie un nouveau contenu sur le site, et que tous ses abonnés (qui, sur une plate-forme comme Twitter, peuvent représenter des millions d’utilisateurs) recevront un message. notification. Dans cette dernière situation, mal structurée, l'envoi d'e-mails peut devenir un goulot d'étranglement dans l'application.

C'est ce qui s'est passé dans mon cas. J'ai un site qui peut avoir besoin d'envoyer 20 courriels après certaines actions déclenchées par l'utilisateur (telles que les notifications d'utilisateur à tous ses abonnés). Initialement, elle utilisait les courriers électroniques via un fournisseur SMTP basé sur un nuage populaire (tels que SendGrid Mandrill Mailjet et Mailgun . ), mais la réponse à l'utilisateur prendrait quelques secondes. Évidemment, la connexion au serveur SMTP pour envoyer ces 20 courriels ralentissait considérablement le processus.

Après inspection, j'ai découvert les sources du problème:

  1. Connexion synchrone
    L'application se connecte au serveur SMTP et attend un accusé de réception, de manière synchrone, avant de poursuivre l'exécution du processus.
  2. Latence élevée
    Alors que mon serveur est situé à Singapour, le fournisseur SMTP que j'utilisais a ses serveurs situés aux États-Unis, ce qui permet la connexion aller-retour.
  3. Pas de possibilité de réutilisation de la connexion SMTP Lors de l'appel de la fonction pour envoyer un courrier électronique, la fonction envoie immédiatement le courrier électronique, créant une nouvelle connexion SMTP à ce moment précis (elle ne propose pas de collecter tous les courriels et envoyez-les tous ensemble à la fin de la demande, sous une seule connexion SMTP.)

En raison de # 1, le temps pendant lequel l'utilisateur doit attendre la réponse est lié au temps nécessaire pour envoyer les courriels. En raison de # 2, le temps d'envoyer un email est relativement élevé. Et à cause du numéro 3, le temps nécessaire pour envoyer 20 courriels est 20 fois le temps qu’il faut pour envoyer un seul courriel. Bien que l'envoi d'un seul courrier électronique ne ralentisse pas considérablement l'application, l'envoi de 20 courriers électroniques en affecte certainement l'expérience utilisateur.

Voyons comment nous pouvons résoudre ce problème.

Faire attention à la nature des courriels transactionnels

Avant tout, il faut remarquer que tous les courriels ne sont pas d'égale importance. Nous pouvons classer les courriers électroniques en deux groupes: les courriers prioritaires et non prioritaires. Par exemple, si l'utilisateur a oublié le mot de passe pour accéder au compte, il attendra immédiatement le courrier électronique contenant le lien de réinitialisation du mot de passe dans sa boîte de réception. c'est un email prioritaire. En revanche, l’envoi d’un courrier électronique indiquant que l’utilisateur suivi a posté un nouveau contenu n’a pas besoin d’arriver immédiatement dans la boîte de réception de l’utilisateur; il s’agit d’un courrier électronique non prioritaire.

La solution doit optimiser la manière dont ces deux catégories d’e-mails sont envoyés. En supposant qu'il n'y aura que quelques (peut-être 1 ou 2) e-mails prioritaires à envoyer pendant le processus et que la plupart des e-mails seront non prioritaires, nous concevons la solution comme suit:

  • E-mails prioritaires peut simplement éviter le problème de latence élevée en utilisant un fournisseur SMTP situé dans la même région que celle où l'application est déployée. En plus d’une bonne recherche, cela implique d’intégrer notre application à l’API du fournisseur.
  • Les e-mails non prioritaires peuvent être envoyés de manière asynchrone et par lots, où de nombreux e-mails sont envoyés ensemble. Mis en œuvre au niveau de l'application, il nécessite une pile de technologies appropriée.

Définissons la pile de technologies permettant d'envoyer des courriels de manière asynchrone.

Définition de la pile de technologies

Note: J'ai décidé de baser ma pile sur les services AWS car mon site Web est déjà hébergé sur AWS EC2. Sinon, le transfert de données entre plusieurs réseaux de sociétés me causerait des frais généraux. Cependant, nous pouvons également mettre en œuvre notre solution en utilisant d'autres fournisseurs de services cloud.

Ma première approche consistait à configurer une file d'attente. Dans une file d'attente, l'application pourrait ne plus envoyer les courriels, mais plutôt publier un message avec le contenu et les métadonnées de l'e-mail dans une file d'attente, puis demander à un autre processus de récupérer les messages dans la file d'attente et de les envoyer.

Cependant, lors de la vérification du service de file d'attente d'AWS, appelé SQS j'ai décidé que ce n'était pas une solution appropriée, car:

  • Il est assez complexe à configurer;
  • Un message de file d'attente standard ne peut stocker que les 256 premiers Ko d’informations, ce qui peut ne pas être suffisant si l’e-mail contient des pièces jointes (une facture par exemple). Et même s'il est possible de scinder un message volumineux en messages plus petits, la complexité augmente encore.

Ensuite, j'ai réalisé que je pouvais parfaitement imiter le comportement d'une file d'attente grâce à une combinaison d'autres services AWS, S3 [ et Lambda qui sont beaucoup plus faciles à configurer. S3, une solution de stockage d'objets dans le cloud permettant de stocker et de récupérer des données, peut servir de référentiel pour le téléchargement des messages, et Lambda, un service informatique qui exécute du code en réponse à des événements, peut sélectionner un message et exécuter une opération avec celui-ci. [19659005] En d’autres termes, nous pouvons configurer notre processus d’envoi d’e-mail comme suit:

  1. L’application télécharge un fichier contenant le contenu de l’e-mail + les métadonnées dans un compartiment S3.
  2. Chaque fois qu’un nouveau fichier est chargé dans le compartiment S3, S3 déclenche un événement contenant le chemin d'accès au nouveau fichier.
  3. Une fonction Lambda sélectionne l'événement, lit le fichier et envoie le courrier électronique.

Enfin, nous devons décider de la méthode d'envoi des courriers électroniques. Nous pouvons soit continuer à utiliser le fournisseur SMTP que nous avons déjà, faire interagir la fonction Lambda avec leurs API, soit utiliser le service AWS pour l'envoi d'e-mails, appelé SES . L’utilisation de SES présente à la fois des avantages et des inconvénients:

Avantages:
  • Très simple à utiliser depuis AWS Lambda (il ne faut que deux lignes de code).
  • C’est moins cher: les frais Lambda sont calculés en fonction du montant de Le temps nécessaire à l'exécution de la fonction est donc nécessaire. Par conséquent, la connexion à SES à partir du réseau AWS prend moins de temps que la connexion à un serveur externe, ce qui rend la fonction plus rapide et moins coûteuse. (À moins que SES ne soit pas disponible dans la même région où l'application est hébergée; dans mon cas, car SES n'est pas proposé dans la région de l'Asie-Pacifique (Singapour), où se trouve mon serveur EC2, il serait peut-être préférable de me connecter à certains Fournisseur SMTP externe basé en Asie).
Inconvénients:
  • Il n’ya pas beaucoup de statistiques sur le contrôle des courriels que nous envoyons, et l’ajout de plus puissants exige des efforts supplémentaires (p. Ex.: Suivi du pourcentage de courriels ouverts ou des liens cliquez sur, doit être configuré via AWS CloudWatch ).
  • Si nous continuons à utiliser le fournisseur SMTP pour l'envoi d'e-mails prioritaires, nous ne disposerons pas de toutes nos statistiques en un seul endroit. [19659020] Pour simplifier, nous utiliserons SES dans le code ci-dessous.

    Nous avons ensuite défini la logique du processus et la pile de la manière suivante: L’application envoie les e-mails prioritaires comme d’habitude, mais pour les non prioritaires, elle télécharge un fichier. avec contenu de courrier électronique et métadonnées vers S3; ce fichier est traité de manière asynchrone par une fonction Lambda qui se connecte à SES pour envoyer le courrier électronique.

    Commençons par implémenter la solution.

    Différenciation des e-mails prioritaires et non prioritaires

    En bref, tout dépend de la application, nous devons donc décider sur un courrier électronique par courrier électronique. Je vais décrire une solution que j'ai implémentée pour WordPress, qui nécessite quelques hacks autour des contraintes de la fonction wp_mail . Pour les autres plates-formes, la stratégie ci-dessous fonctionnera également, mais il y aura peut-être de meilleures stratégies, qui ne nécessitent pas de piratage.

    Pour envoyer un courrier électronique dans WordPress, vous pouvez appeler la fonction wp_mail . , et nous ne voulons pas changer cela (par exemple: en appelant l'une des fonctions wp_mail_synchronous ou wp_mail_asynchronous ), notre implémentation de wp_mail devra gérer les deux cas synchrones et asynchrones, et aura besoin de savoir à quel groupe l'e-mail appartient. Malheureusement, wp_mail n'offre aucun paramètre supplémentaire à partir duquel nous pourrions évaluer cette information, comme il ressort de sa signature:

    fonction wp_mail ($ to, $ sujet, $ message, $ en-têtes) = '', $ attachments = array ()) 

    Ensuite, afin de connaître la catégorie de l'e-mail, nous ajoutons une solution hacky: par défaut, nous faisons en sorte qu'un e-mail appartienne au groupe de priorités, et si $ à contient un email particulier (par exemple: nonpriority@asynchronous.mail), ou si $ subject commence par une chaîne spéciale (par exemple: “[Non-priority!]"), il appartient au non -groupe de priorité (et nous supprimons l'email ou la chaîne correspondante de l'objet). wp_mail est une fonction enfichable. Nous pouvons donc la remplacer simplement en implémentant une nouvelle fonction avec la même signature sur notre fichier functions.php. Initialement, il contient le même code que la fonction wp_mail d'origine, située dans le fichier wp-includes / pluggable.php, pour extraire tous les paramètres:

     if (! Function_exists ('wp_mail')):
    
    function wp_mail ($ to, $ subject, $ message, $ headers = '', $ attachments = array ()) {
    
      $ atts = apply_filters ('wp_mail', compact ('à', 'sujet', 'message', 'en-têtes', 'pièces jointes'));
    
      if (isset ($ atts ['to'])) {
        $ to = $ atts ['to'];
      }
    
      if (! is_array ($ to)) {
        $ to = exploser (',', $ to);
      }
    
      if (isset ($ atts ['subject'])) {
        $ subject = $ atts ['subject'];
      }
    
      if (isset ($ atts ['message'])) {
        $ message = $ atts ['message'];
      }
    
      if (isset ($ atts ['headers'])) {
        $ headers = $ atts ['headers'];
      }
    
      if (isset ($ atts ['attachments'])) {
        $ attachments = $ atts ['attachments'];
      }
    
      if (! is_array ($ attachments)) {
        $ attachments = explode (" n", str_replace (" r  n", " n", $ attachments));
      }
      
      // Continuer ci-dessous ...
    }
    fin si;
    

    Nous vérifions ensuite si elle est non prioritaire, auquel cas nous basculons vers une logique distincte sous la fonction send_asynchronous_mail ou, si ce n'est pas le cas, nous continuons à exécuter le même code que dans l'original. wp_mail fonction:

     fonction wp_mail ($ à, sujet, $ message, $ en-têtes = '', $ pièces jointes = array ()) {
    
      // Suite d'en haut ...
    
      $ hacky_email = "nonpriority@asynchronous.mail";
      if (in_array ($ hacky_email, $ to)) {
    
        // Supprimer l'email hacky de $ à
        array_splice ($ to, array_search ($ hacky_email, $ to), 1);
    
        // Fork vers la logique asynchrone
        return send_asynchronous_mail ($ to, $ subject, $ message, $ headers, $ attachments);
      }
    
      // Continuer tout le code de la fonction d'origine dans wp-includes / pluggable.php
      // ...
    }
    

    Dans notre fonction send_asynchronous_mail au lieu de télécharger le courrier électronique directement sur S3, nous ajoutons simplement le courrier électronique à une variable globale $ emailqueue à partir de laquelle nous pouvons télécharger tous les courriers électroniques ensemble. S3 dans une connexion unique à la fin de la demande:

     function send_asynchronous_mail ($ to, $ subject, $ message, $ headers, $ attachments) {
      
      global $ emailqueue;
      si (! $ emailqueue) {
        $ emailqueue = array ();
      }
      
      // Ajouter un email à la file d'attente. Le code continue ci-dessous ...
    }
    

    Nous pouvons télécharger un fichier par courrier électronique ou les regrouper afin que, dans un fichier, nous ayons plusieurs courriers électroniques. Depuis que $ headers contient une méta de courrier électronique (à partir des champs content-type et charset, CC, BCC et Reply-to), nous pouvons regrouper les courriers électroniques à chaque fois qu'ils ont le même $ headers . . De cette façon, ces courriels peuvent tous être téléchargés dans le même fichier vers S3 et les méta-informations $ headers ne seront incluses qu'une seule fois dans le fichier, au lieu d'une fois par courriel:

     function send_asynchronous_mail ($ to, $ subject, $ message, $ headers, $ attachments) {
      
      // Suite d'en haut ...
    
      // Ajouter un email à la file d'attente
      $ emailqueue [$headers] = $ emailqueue [$headers] ?? tableau ();
      $ emailqueue [$headers][]  = array (
        'to' => $ to,
        'sujet' => $ sujet,
        'message' => $ message,
        'attachments' => $ attachments,
      )
    
      // Le code continue ci-dessous
    }
    

    Enfin, la fonction send_asynchronous_mail renvoie true . Veuillez noter que ce code est hacky: true signifierait normalement que le courrier électronique a été envoyé avec succès, mais dans ce cas, il n’a pas encore été envoyé et il pourrait parfaitement échouer. De ce fait, la fonction appelant wp_mail ne doit pas traiter une réponse vraie comme "le courrier électronique a été envoyé avec succès", mais un accusé de réception indiquant qu'il a été mis en file d'attente. C'est pourquoi il est important de limiter cette technique aux courriers électroniques non prioritaires afin qu'en cas d'échec, le processus puisse continuer à réessayer en arrière-plan et que l'utilisateur ne s'attende pas à ce que le courrier électronique soit déjà dans sa boîte de réception:

     function send_asynchronous_mail ( $ to, $ subject, $ message, $ headers, $ attachments) {
      
      // Suite d'en haut ...
    
      // C'est tout!
      retourne vrai;
    }
    

    Téléchargement d'e-mails vers S3

    Dans mon article précédent, intitulé [ Partage de données entre plusieurs serveurs via AWS S3 je décrivais comment créer un compartiment dans S3 et comment télécharger des fichiers dans le compartiment via le SDK. Tout le code ci-dessous continue l'implémentation d'une solution pour WordPress, nous nous connectons donc à AWS à l'aide du SDK pour PHP.

    Nous pouvons étendre la classe abstraite AWS_S3 (introduite dans mon précédent article) à S3 et chargez les courriels dans un «s-mail asynchrone» à la fin de la demande (déclenché par le crochet wp_footer ). Veuillez noter que nous devons garder la liste de contrôle d'accès comme «privée» car nous ne voulons pas que les courriels soient exposés à Internet:

     class AsyncEmails_AWS_S3 étend AWS_S3 {
    
      fonction __construct () {
    
        // Envoyer tous les emails à la fin de l'exécution
        add_action ("wp_footer", tableau ($ this, "upload_emails_to_s3"), PHP_INT_MAX);
      }
    
      fonction protégée get_acl () {
    
        retourner "privé";
      }
    
      fonction protégée get_bucket () {
    
        renvoyer "async-emails";
      }
    
      fonction upload_emails_to_s3 () {
    
        $ s3Client = $ this-> get_s3_client ();
    
        // Code continué ci-dessous ...
      }
    }
    new AsyncEmails_AWS_S3 ();
    

    Nous commençons à parcourir les paires d'en-têtes => emaildata enregistrées dans la variable globale $ emailqueue et obtenons une configuration par défaut de la fonction get_default_email_meta si les en-têtes sont vides. Dans le code ci-dessous, je récupère uniquement le champ "de" à partir des en-têtes (le code permettant d'extraire tous les en-têtes peut être copié à partir de la fonction d'origine wp_mail ):

     de la classe AsyncEmails_AWS_S3 étend AWS_S3 {
    
      fonction publique get_default_email_meta () {
    
        // Code continué d'en haut ...
    
        retourne un tableau (
          'from' => sprintf (
            '% s',
            get_bloginfo ('nom'),
            get_bloginfo ('admin_email')
          ),
          'contentType' => 'text / html',
          'charset' => strtolower (get_option ('blog_charset'))
        )
      }
    
      fonction publique upload_emails_to_s3 () {
    
        // Code continué d'en haut ...
    
        global $ emailqueue;
        foreach ($ emailqueue as $ headers => $ emails) {
    
          $ meta = $ this-> get_default_email_meta ();
    
          // Récupère le "from" des en-têtes
          $ regexp = '/ From:  s * (([^?s*n/i';
          if(preg_match($regexp, $headers, $matches)) {
            
            $meta['from'] = sprintf (
              '% s',
              $ correspondances [2],
              $ correspondances [3]
            )
          }
    
          // Code continué ci-dessous ...
        }
      }
    }
    

    Enfin, nous téléchargeons les courriels vers S3. Nous décidons combien d'e-mails télécharger par fichier avec l'intention d'économiser de l'argent. Les fonctions Lambda facturent en fonction de la durée d'exécution requise, calculée sur une durée de 100 ms. Plus une fonction prend du temps, plus elle coûte cher.

    L'envoi de tous les courriels en téléchargeant un fichier par courriel est plus onéreux que le téléchargement d'un fichier par plusieurs courriels, car le temps système nécessaire à l'exécution de la fonction est calculé une fois par jour. e-mail, au lieu d'une seule fois pour de nombreux e-mails, et aussi parce que l'envoi simultané de plusieurs e-mails remplit la plage de 100 ms de manière plus complète.

    Nous téléchargeons donc plusieurs e-mails par fichier. Combien d'emails? Les fonctions Lambda ont un temps d'exécution maximum (3 secondes par défaut), et si l'opération échoue, les tentatives sont répétées depuis le début, pas depuis l'échec. Ainsi, si le fichier contient 100 e-mails et que Lambda parvient à envoyer 50 e-mails avant l'expiration du délai maximal, le système échoue et il réessaie d'exécuter l'opération en renvoyant les 50 premiers e-mails. Pour éviter cela, nous devons choisir un nombre de courriels par fichier que nous sommes certains de pouvoir traiter avant la fin du délai maximal. Dans notre cas, nous pourrions choisir d'envoyer 25 courriels par fichier. Le nombre d'e-mails dépend de l'application (les e-mails volumineux prendront plus de temps et le temps nécessaire pour envoyer un e-mail dépend de l'infrastructure), nous devrions donc faire quelques essais pour trouver le bon numéro.

    le contenu du fichier est simplement un objet JSON, contenant la méta de courrier électronique sous la propriété "méta" et la partie des courriers électroniques sous la propriété "emails":

     classe AsyncEmails_AWS_S3 étend AWS_S3 {
    
      fonction publique upload_emails_to_s3 () {
    
        // Code continué d'en haut ...
        foreach ($ emailqueue as $ headers => $ emails) {
    
          // Code continué d'en haut ...
    
          // Diviser les courriels en morceaux ne dépassant pas la valeur de la constante EMAILS_PER_FILE:
          $ chunks = array_chunk ($ emails, EMAILS_PER_FILE);
          $ filename = time (). rand ();
          pour ($ chunk_count = 0; $ chunk_count $ meta,
              'emails' => $ chunks [$chunk_count],
            )
    
            // Transférer vers S3
            $ s3Client-> putObject ([
              'ACL' => $this->get_acl(),
              'Bucket' => $this->get_bucket(),
              'Key' => $filename.$chunk_count.'.json',
              'Body' => json_encode($body),
            ]);
          }
        }
      }
    }
    

    Par souci de simplicité, dans le code ci-dessus, je ne télécharge pas les pièces jointes vers S3. Si nos courriels doivent inclure des pièces jointes, nous devons alors utiliser la fonction SES SendRawEmail au lieu de SendEmail (utilisée dans le script Lambda ci-dessous).

    Après avoir ajouté la logique de téléchargement Pour les fichiers contenant des e-mails vers S3, nous pouvons passer au codage de la fonction Lambda.

    Codage du script Lambda

    Les fonctions Lambda sont également appelées fonctions sans serveur, non pas parce qu'elles ne s'exécutent pas sur un serveur, mais parce que le développeur vous n'avez pas à vous soucier du serveur: le développeur fournit simplement le script et le cloud se charge de provisionner le serveur, de déployer et d'exécuter le script. Par conséquent, comme indiqué précédemment, les fonctions Lambda sont facturées en fonction de leur temps d'exécution.

    Le script Node.js suivant effectue le travail requis. Appelé par l'événement "Put" S3, qui indique qu'un nouvel objet a été créé sur le compartiment, la fonction:

    1. Obtient le chemin du nouvel objet (sous la variable srcKey ) et le compartiment (sous la variable srcBucket ).
    2. Télécharge l'objet via s3.getObject .
    3. Analyse le contenu de l'objet via JSON.parse (response.Body.toString ( )) et extrait les e-mails et la méta d'email.
    4. Parcourt tous les e-mails et les envoie via ses.sendEmail .
     var async = require ('async') ;
    var aws = require ('aws-sdk');
    var s3 = new aws.S3 ();
          
    exports.handler = function (événement, contexte, rappel) {
    
      var srcBucket = event.Records [0] .s3.bucket.name;
      var srcKey = decodeURIComponent (event.Records [0] .s3.object.key.replace (/  + / g, ""));
    
      // Téléchargez le fichier depuis S3, analysez-le et envoyez les emails.
      async.waterfall ([
    
        téléchargement de fonction (suivant) {
    
          // Téléchargez le fichier de S3 dans un tampon.
          s3.getObject ({
            Seau: srcBucket,
            Clé: srcKey
          }, suivant);
        },
        processus de fonction (réponse, suivant) {
              
          var fichier = JSON.parse (response.Body.toString ());
          var emails = file.emails;
          var emailsMeta = file.meta;
            
          // Vérifier les paramètres requis
          if (emails === null || emailsMeta === null) {
            callback ('Requête incorrecte: données requises manquantes:' + response.Body.toString ());
            revenir;
          }
          if (emails.length === 0) {
            callback ('Bad Request: Aucun email fourni:' + response.Body.toString ());
            revenir;
          }
          
          var totalEmails = emails.length;
          var sentEmails = 0;
          for (var i = 0; i 

    Ensuite, nous devons télécharger et configurer la fonction Lambda sur AWS, ce qui implique:

    1. Création d'un rôle d'exécution accordant des autorisations Lambda pour accéder à S3.
    2. Création d'un package .zip contenant tout le code, c’est-à-dire la fonction Lambda que nous créons + tous les modules Node.js requis.
    3. Téléchargement de ce package vers AWS à l’aide d’un outil CLI

    La procédure à suivre est expliquée correctement sur le site AWS, sur le Tutoriel sur l'utilisation d'AWS Lambda avec Amazon S3 .

    Raccordement de S3 à la fonction Lambda

    Enfin, pour que le seau et la fonction Lambda soient créés, nous devons associer les deux fonctions ensemble, afin que chaque fois qu’un nouvel objet est créé sur le compartiment, un événement est exécuté pour exécuter la fonction Lambda. Pour ce faire, nous allons au tableau de bord S3 et cliquez sur la ligne du compartiment, ce qui affichera son properties:


     Affichage des propriétés de compartiment dans le tableau de bord S3
    En cliquant sur le bouton La ligne de compartiment affiche les propriétés du compartiment. ( Grand aperçu )

    Cliquez ensuite sur Propriétés pour faire défiler jusqu'à l'élément "Événements", puis cliquez sur Ajouter une notification et saisissez les champs suivants:

    • Nom: nom de la notification, par exemple: "EmailSender ”;
    • Événements: “ Put ”, qui est l'événement déclenché lorsqu'un nouvel objet est créé sur le seau;
    • Envoyer à: “ Fonction Lambda ”;
    • Lambda: nom de notre Lambda nouvellement créé, par exemple: «LambdaEmailSender».

     Configuration de S3 avec Lambda
    Ajout d'une notification dans S3 pour déclencher un événement pour Lambda. ( Grand aperçu )

    Enfin, nous pouvons également configurer le compartiment S3 pour qu'il supprime automatiquement les fichiers contenant les données de courrier électronique après un certain temps. Pour cela, ouvrez l'onglet Gestion du compartiment et créez une nouvelle règle de cycle de vie définissant après combien de jours les e-mails doivent expirer:


     Règle de cycle de vie
    Configuration d'une règle de cycle de vie pour supprimer automatiquement les fichiers du compartiment . ( Grand aperçu )

    C’est tout. À partir de ce moment, lors de l'ajout d'un nouvel objet sur le compartiment S3 avec le contenu et la méta des e-mails, la fonction Lambda sera déclenchée, ce qui lira le fichier et se connectera à SES pour envoyer les e-mails.

    J'ai implémenté cette solution. sur mon site, et tout redevint rapide: en déchargeant l'envoi d'e-mails vers un processus externe, que les applications envoient 20 ou 5 000 e-mails ne faisant aucune différence, la réponse à l'utilisateur qui a déclenché l'action sera immédiate. [19659099] Conclusion

    Dans cet article, nous avons analysé les raisons pour lesquelles l'envoi de plusieurs courriels transactionnels en une seule demande pouvait devenir un goulot d'étranglement dans l'application. Nous avons donc créé une solution permettant de résoudre le problème: au lieu de vous connecter au serveur SMTP à partir de l'application ( de manière synchrone), nous pouvons envoyer les e-mails d’une fonction externe, de manière asynchrone, sur la base d’une pile d’AWS S3 + Lambda + SES.

    En envoyant des e-mails de manière asynchrone, l’application peut gérer l’envoi de milliers l'utilisateur qui a déclenché l'action ne sera pas affecté. Toutefois, afin de s’assurer que l’utilisateur n’attend pas que le courrier électronique arrive dans la boîte de réception, nous avons également décidé de scinder les courriers électroniques en deux groupes, prioritaire et non prioritaire, et d’envoyer uniquement les courriers électroniques non prioritaires de manière asynchrone. Nous avons fourni une implémentation pour WordPress, ce qui est plutôt fastidieux en raison des limitations de la fonction pour l'envoi d'e-mails par wp_mail .

    L'un des enseignements de cet article est que les fonctionnalités sans serveur sur une application basée sur serveur fonctionnent plutôt bien: Les sites fonctionnant sur un CMS tel que WordPress peuvent améliorer leurs performances en n'implémentant que des fonctionnalités spécifiques sur le cloud et en évitant toute la complexité liée à la migration de sites très dynamiques vers une architecture sans serveur.

     Smashing Editorial (rb , ra, yk, il)




Source link