Traiter les mails entrants avec Apex Email Service

Traiter les mails entrants avec Apex Email Service

Dans ce nouvel article, nous restons dans la thématique des emails (cf Article 14 sur l’envoi de mail avec template sans contact) en présentant l’interface Messaging.InboundEmailHandler.

Cette interface permet d’appliquer un traitement Apex suite à la réception d’un mail entrant. Cela ressemble dans l’esprit à Email-To-Case, fonctionnalité standard qui permet de créer un ticket (case) suite à la réception d’un mail entrant. Les détails de cette interface ainsi qu’un exemple sont fournis dans l’Apex Developer Guide.

Cette fonctionnalité contribue aux mêmes limites (governor limits) que les emails entrants traités dans le cadre de On-Demand Email-to-Case. Elles sont rappelées ici.

Dans le but de nous familiariser avec cette interface, nous allons dérouler le 2e scénario décrit dans l’aide Salesforce. Sur chaque contact, existe un champ standard Email Opt Out qui permet d’indiquer si le contact souhaite ne plus recevoir de communications commerciales :

Contact Email Opt Out décoché

N.B. : il est possible que par défaut, ce champ ne soit visible pour aucun profil. Son API name est « hasOptedOutOfEmail ». Penser à paramétrer les FLS sur ce champ. Pour plus de détails, lire cet article de l’aide Salesforce.

Créer une classe implémentant l’interface Messaging.InboundEmailHandler

Il faut tout d’abord créer une classe QuitterNewsLetter qui implémente notre interface :

global class QuitterNewsLetter implements Messaging.InboundEmailHandler {
	  global Messaging.InboundEmailResult handleInboundEmail(Messaging.InboundEmail email, Messaging.InboundEnvelope envelope) {
		  Messaging.InboundEmailResult result = new Messaging.InboundEmailresult();
          return result;
      }
  }

Il s’agit d’un pré-requis pour la suite du paramétrage. Nous pourrons compléter le contenu de cette classe Apex ensuite.

Classe implémentant Messaging.InboundEmailHandler

Définir un Apex Email Service

Afin de faire le lien entre un email reçu à une adresse spécifique et un traitement Apex à déclencher, nous allons définir un Apex Email Service.

Depuis Setup | Email Services, cliquer sur le bouton New Email Service.

Nous renseignons ici un minimum de champs :

  • Email Service Name = Désabonnement newsletter
  • Apex Class = QuitterNewsLetter
  • Active = True
Créer un Email Service

Cliquer sur Save.

D’autres options existent comme la possibilité de router les messages d’erreur à une adresse spécifique :

Options d'un email service

Attention, il est possible qu’un message d’erreur s’affiche bien que la classe implémente la bonne interface :

The Apex Class selected is not valid. An Apex Class that implements the Messaging.InboundEmailHandler interface must be selected.

Bug Apex Email Service

Pour résoudre ce qui s’avère être un bug, il faut potentiellement supprimer et recréer la classe. Une recompilation des classes (via Setup | Apex classes | Compile all Classes) peut également aider.

Associer une adresse email technique

Poursuivre le paramétrage en associant une adresse email technique à cet Email Service. Pour ce faire, depuis la liste associée « Email adresses », cliquer sur le bouton New Email Address :

Ajout d'adresse sur Email Service

Voici les champs proposés :

  • Email Address Name = UnsubscribeNewsletter. Ce nom ne doit pas contenir d’espaces. On va retrouver ce nom dans la liste des adresses associées à l’Email Service car il peut y en avoir plusieurs.
  • Email Address = Desabonnement_newletter. Ce champ est pré-renseigné par défaut. Il va servir de racine (partie à gauche de l’@) de l’adresse mail technique que l’on crée.
  • Active = True
  • Context User = Pascal Taghji. La classe Apex va se servir de cet utilisateur pour exécuter le code Apex associé à l’email service. Il faut donc veiller à ce que cet utilisateur ait suffisamment de droits.
  • Accept Email From = <vide>. Par défaut, ce champ reprend l’adresse mail de l’utilisateur courant. Nous le vidons ici afin de permettre le fonctionnement depuis n’importe quelle adresse. Par la suite, ceci peut être affiné car il s’agit d’un mécanisme de sécurité pour éviter d’être spammé.

Une fois l’adresse créée, on voit une adresse email technique apparaitre. On va pouvoir la copier afin de la tester et l’utiliser par la suite :

Adresse email technique

N.B. : On retrouve ce type d’adresses techniques dans la fonctionnalité Email to Salesforce. Pour rappel, celle-ci permet de lier automatiquement un email à un lead dans Salesforce, contact si l’on précise en copie cachée l’adresse technique.

Attention, on peut rencontrer l’erreur suivante suite à la sauvegarde : « The email address is not valid »

Email address not valid

L’erreur ci-dessus a été obtenue en saisissant Désabonnement_newsletter dans le champ Email Address. En effet, l’accentuation n’est pas acceptée. Se référer à l’aide Salesforce pour plus de détails sur les caractères autorisés.

Enrichir la classe Apex et tester

Afin de pouvoir démarrer, nous avons créé une classe Apex lors de la première étape. En s’inspirant de l’exemple fourni dans l’aide Salesforce et en l’adaptant, cela donne :

/**************************************************************************************************
* @date         21/10/2022
* @author       Pascal TAGHJI
* @jira         Article 15 du blog BC-data
* @group        Prise de Commande
* @test         QuitterNewsLetterTest
* @description 	Traite un email rentrant de demande de désabonnement à des newsletter
*               Le but est de cocher la case "Email Opt Out" d'un contact pour ne plus le solliciter
**************************************************************************************************/
global class QuitterNewsLetter implements Messaging.InboundEmailHandler {
    global Messaging.InboundEmailResult handleInboundEmail(Messaging.InboundEmail email, Messaging.InboundEnvelope envelope) {
        Messaging.InboundEmailResult result = new Messaging.InboundEmailresult();
        
        // Liste des contacts à désabonner
        List<Contact> contactsToUnsub = new List <contact>();
        
        // Mot clé à détecter dans l'objet du mail pour appliquer le désabonnement
        String subjectKeyWord = 'unsubscribe';
        
        // Récupérer l'objet du mail et le convertir en minuscule (pour comparaison) + expéditeur du mail
        String mySubject = email.subject.toLowerCase();
        //String expediteur = envelope.fromAddress;
        String expediteur =  'antinewsart15@yopmail.com';
        
        // Vérifier si l'objet du mail contient le mot clé
        Boolean unsubMe = mySubject.contains(subjectKeyWord);
        
        if (unsubMe) { 
            try {
                // Rechercher si des contacts correspondent (= même adresse mail) à cet expéditeur
                for (Contact c : [SELECT Id, Name, Email, HasOptedOutOfEmail FROM Contact
                                  WHERE Email = :expediteur AND hasOptedOutOfEmail = false]) {  
                    c.hasOptedOutOfEmail = true;
                    contactsToUnsub.add(c);
                }
                // Désabonner les contacts (en décochant "Email Opt Out")
                update contactsToUnsub;
            } catch (System.QueryException e) {
                System.debug('Contact Query Issue: ' + e);
            }
            system.debug('Mot clé ' + subjectKeyWord + ' trouvé. Désabonnement effectué pour : ' + contactsToUnsub);        
        } else {
            system.debug('Mot clé ' + subjectKeyWord + ' absent du sujet du mail.');
        }
        
        // True confirme que le code s'est bien exécuté
        // Pas besoin de renvoyer un mail à l'expéditeur de la demande de désabonnement
        result.success = true;
        
        return result;
    }
}

Il ne reste plus qu’à tester en envoyant un mail :

Test envoi email

Suite  à ce test, tous les contacts ayant la même adresse email que l’expéditeur verront leur case Email Opt Out cochée :

Contact Email Opt Out coché