Bonjour à tous,
J’ai mis en place un moyen d’envoyer des alertes mails avec des composantes de temps et des conditions.
Par exemple :
Je veux envoyer une alerte mail trois mois après la création de d’un rdv si et seulement si l’ia n’a pas confirmé son rdv. Je veux relancer l’IA avec son manager en copie.
Cette exemple comporte plusieurs points :
- Les workflows ne sont pas disponibles sur la table des activités (événements et tâches)
- Les workflows permettent de faire des relances avec une composante de temps mais sans réévaluer la règle ni ajouter une condition.
- Salesforce limite les envois de mail via APEX à 1000 mails par jour.
Dans ce cas, où on ne peux pas envoyer de mail natif. La classe va permettre de le faire.
En APEX, en fonction des critères nous allons préparer un envoi de mails en masse, via les méthodes génériques de la classe MailTemp.
Cette même classe est schedulable donc un script sera inséré dans les tâches prévues afin de lancer les alertes mails à une heure choisie.
Passons maintenant sur un aspect un peu plus technique.
Les limitations notamment, cette classe à quelques inconvénients mineurs.
- On ne pourra pas mettre des destinataires en Cc (Copie carbone) ou Cci (Copie carbone invisible)
- La classe est limité à 50 Workflows actifs, soit 50 templates mails en quelque sorte. Je rappelle qu’en même temps normalement la plupart des alertes est faisable en natif.
- L’Apex ne prend pas en charge la réflection comme le fait JAVA ou le C#, de ce fait nous sommes obligés d’affecter chaque valeur à la main sans pouvoir faire de boucle … (Voir dans la classe l’affectation des mails et des fields dans la méthode PrepareMailGenerique) Si vous trouvez un moyen plus sexy je suis preneur !
D’autres limitations qui peuvent être, elles, modulables :
- 40 destinataire maximum par mail
- 30 champs texte de mapping disponible
Comme une classe est limitée à 500 champs customs on pourrait bien sûr, si besoin, améliorer la classe pour prendre en compte plus de mails ou de champs. Mais dans notre cas ce n’est pour le moment, pas nécessaire.
D’autres limites peuvent intervenir en cas d’envoi de mails en masse de plus de 2000 mails d’un coup. Dans ce cas je vous invite à (re)lire la documentation sur les limites.
L’utilisation maintenant :
La classe permet de stacker des mails , elle les insères en base. Une fois inséré, un workflow sur les insert se déclenche et envoi le mail avec le bon template.
La classe comporte un exemple commenté qui est EnvoiMailCom().
- Comment savoir si c’est le bon template ?
Le champ Name de l’objet va servir d’id.
Exemple : name = « MAIL_COMM »
Mon workflow aura comme conditions : Si Email1__c différent de vide ET Name == ‘MAIL_COMM’ alors OK
- Qu’advient-il des éléments insérés en base ?
Les éléments en base restent stockés. Par contre un champ case à cocher sur l’objet ‘Archive’ va permettre de voir si le mail est bien envoyé ou non.
C’est pour ça que le workflow en plus de l’alerte mail devra mettre à jour ce champs en ‘True’. Et comme on est jamais trop prudent on pourra rajouter cette condition dans la règle du workflow.
Pour reprendre l’exemple ci-dessous ça donnera : Si Email1__c différent de vide ET Name == ‘MAIL_COMM’ ET Archive différent de True alors OK
-Comment savoir comment faire le matching ? Les champs de matching sont en format string et j’ai des dates comment faire ?
La partie mapping est à vous de le gérer. Vous gérer votre alerte de façon à ce que tout coordonne.
Les champs sont tous en format string, à vous de les caster afin qu’il y ait pas de soucis.
Le prototype de la fonction de préparation :
public static list<TamponMail__c> PrepareMailGenerique(list<string> lmail, list<string> lfield, string nom, string objet, list<TamponMail__c> lTempMail)
Valeur de retour : Liste de mails (pour pouvoir les empilés)
Arguments :
- lmail : Liste de mails (40 éléments maxi), un élément de la liste == un mail.
- lfield : Liste des champs customs (30 éléments maxi), un élément de la liste == un champ à matcher dans le template du mail sur Salesforce.
- nom : Champ texte qui permet de gérer par la suite les workflows
- objet : champs texte qui représente l’objet du mail
- lTempMail : Pareil que la valeur de retour c’est pour pouvoir empiler les mails
Le prototype de la fonction d’envoi :
public static void EnvoiMailGenerique(list<TamponMail__c> tmail)
Valeur de retour : Aucune, elle clôture le traitement en envoyant intégralement la liste de mail, théoriquement lTempMail.
Argument :
- tmail : une liste permettant d’envoyer tous les mails. (Je conseille d’éviter de dépasser les 2000, après plusieurs tests le comportement au dessus de 2000 mail envoyé est aléatoire. Souvent Salesforce retourne une erreur interne)
Pour finir dans la méthode schedulable il faut mettre les méthodes qui envoient les mails et qui se servent des méthodes de la classe MailTemp.cls

Je mets à disposition un package regroupant la classe, l’objet et ses champs, afin de pas avoir besoin de tout créer sur sa sandbox pour faire des tests si besoin. https://test.salesforce.com/packagin...4tW00000004t2U
Voici la classe :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
| // Réalisé par Ludovic Marboutie le 03/01/2013
// Pour éviter de dépasser les limites de SF(1000 mail max par jour). La les mails sont déclenché par worklow sur la classe.
/* LIMITES :
- Prend en charge 50 alertes mails (limite de workflow par classe)
- Les champs customs sont limités à 30
- Ils doivent être formaté en string donc à vous de concaténer comme il faut.
- Attention au mapping.
- Les mails insérés sont limités à 40
- Attention ils apparaissent tous dans la zone "A:" donc pas possible de mettre en copie
les envois de mails seront tous destinataire. C'est le petit truc que j'ai pas réussi à faire.
- Le Nom est là pour faire office d'id pour déclencher le bon workflow avec la bonne alerte mail et surtout le bon template.
- L'objet c'est l'objet rien de particulier.
- le dernier arguement de la methode prépare est pour empiler les envois de mail.
*/
global class MailTemp implements Schedulable
{
global void execute(SchedulableContext ctx)
{
//insérer tout les méthodes d'envoi de mail pour balancer une seule tache à 23h
// Aucune traitement métier ne doit apparaitre dans cette classe afin de la garder le plus générique possible.
//déclenche les méthodes métier qui se servent des méthodes de cette classe.
// EnvoiMailCom();
}
public static list<TamponMail__c> PrepareMailGenerique(list<string> lmail, list<string> lfield, string nom, string objet, list<TamponMail__c> lTempMail)
{
TamponMail__c tmail = new TamponMail__c();
//affectation d'un 'id' pour la reconnaissance de l'alerte par le workflow
tmail.Name = nom;
tmail.Objet__c = objet;
//Note : La reflection en APEX n'est pas encore possible donc obligé de faire l'affectation à la main...
//affectation des mails.
if (lmail.size() > 0)
tmail.Email1__c = lmail.get(0);
if (lmail.size() > 1)
tmail.Email2__c = lmail.get(1);
if (lmail.size() > 2)
tmail.Email3__c = lmail.get(2);
if (lmail.size() > 3)
tmail.Email4__c = lmail.get(3);
if (lmail.size() > 4)
tmail.Email5__c = lmail.get(4);
if (lmail.size() > 5)
tmail.Email6__c = lmail.get(5);
if (lmail.size() > 6)
tmail.Email7__c = lmail.get(6);
if (lmail.size() > 7)
tmail.Email8__c = lmail.get(7);
if (lmail.size() > 8)
tmail.Email9__c = lmail.get(8);
if (lmail.size() > 9)
tmail.Email10__c = lmail.get(9);
if (lmail.size() > 10)
tmail.Email11__c = lmail.get(10);
if (lmail.size() > 11)
tmail.Email12__c = lmail.get(11);
if (lmail.size() > 12)
tmail.Email13__c = lmail.get(12);
if (lmail.size() > 13)
tmail.Email14__c = lmail.get(13);
if (lmail.size() > 14)
tmail.Email15__c = lmail.get(14);
if (lmail.size() > 15)
tmail.Email16__c = lmail.get(15);
if (lmail.size() > 16)
tmail.Email17__c = lmail.get(16);
if (lmail.size() > 17)
tmail.Email18__c = lmail.get(17);
if (lmail.size() > 18)
tmail.Email19__c = lmail.get(18);
if (lmail.size() > 19)
tmail.Email20__c = lmail.get(19);
if (lmail.size() > 20)
tmail.Email21__c = lmail.get(20);
if (lmail.size() > 21)
tmail.Email22__c = lmail.get(21);
if (lmail.size() > 22)
tmail.Email23__c = lmail.get(22);
if (lmail.size() > 23)
tmail.Email24__c = lmail.get(23);
if (lmail.size() > 24)
tmail.Email25__c = lmail.get(24);
if (lmail.size() > 25)
tmail.Email26__c = lmail.get(25);
if (lmail.size() > 26)
tmail.Email27__c = lmail.get(26);
if (lmail.size() > 27)
tmail.Email28__c = lmail.get(27);
if (lmail.size() > 28)
tmail.Email29__c = lmail.get(28);
if (lmail.size() > 29)
tmail.Email30__c = lmail.get(29);
if (lmail.size() > 30)
tmail.Email31__c = lmail.get(30);
if (lmail.size() > 31)
tmail.Email32__c = lmail.get(31);
if (lmail.size() > 32)
tmail.Email33__c = lmail.get(32);
if (lmail.size() > 33)
tmail.Email34__c = lmail.get(33);
if (lmail.size() > 34)
tmail.Email35__c = lmail.get(34);
if (lmail.size() > 35)
tmail.Email36__c = lmail.get(35);
if (lmail.size() > 36)
tmail.Email37__c = lmail.get(36);
if (lmail.size() > 37)
tmail.Email38__c = lmail.get(37);
if (lmail.size() > 38)
tmail.Email39__c = lmail.get(38);
if (lmail.size() > 39)
tmail.Email40__c = lmail.get(39);
//Note : La reflection en APEX n'est pas encore possible donc obligé de faire l'affectation à la main...
//affectation des champs custom
if (lfield.size() > 0)
tmail.field1__c = lfield.get(0);
if (lfield.size() > 1)
tmail.field2__c = lfield.get(1);
if (lfield.size() > 2)
tmail.field3__c = lfield.get(2);
if (lfield.size() > 3)
tmail.field4__c = lfield.get(3);
if (lfield.size() > 4)
tmail.field5__c = lfield.get(4);
if (lfield.size() > 5)
tmail.field6__c = lfield.get(5);
if (lfield.size() > 6)
tmail.field7__c = lfield.get(6);
if (lfield.size() > 7)
tmail.field8__c = lfield.get(7);
if (lfield.size() > 8)
tmail.field9__c = lfield.get(8);
if (lfield.size() > 9)
tmail.field10__c = lfield.get(9);
if (lfield.size() > 10)
tmail.field11__c = lfield.get(10);
if (lfield.size() > 11)
tmail.field12__c = lfield.get(11);
if (lfield.size() > 12)
tmail.field13__c = lfield.get(12);
if (lfield.size() > 13)
tmail.field14__c = lfield.get(13);
if (lfield.size() > 14)
tmail.field15__c = lfield.get(14);
if (lfield.size() > 15)
tmail.field16__c = lfield.get(15);
if (lfield.size() > 16)
tmail.field17__c = lfield.get(16);
if (lfield.size() > 17)
tmail.field18__c = lfield.get(17);
if (lfield.size() > 18)
tmail.field19__c = lfield.get(18);
if (lfield.size() > 19)
tmail.field20__c = lfield.get(19);
if (lfield.size() > 20)
tmail.field21__c = lfield.get(20);
if (lfield.size() > 21)
tmail.field22__c = lfield.get(21);
if (lfield.size() > 22)
tmail.field23__c = lfield.get(22);
if (lfield.size() > 23)
tmail.field24__c = lfield.get(23);
if (lfield.size() > 24)
tmail.field25__c = lfield.get(24);
if (lfield.size() > 25)
tmail.field26__c = lfield.get(25);
if (lfield.size() > 26)
tmail.field27__c = lfield.get(26);
if (lfield.size() > 27)
tmail.field28__c = lfield.get(27);
if (lfield.size() > 28)
tmail.field29__c = lfield.get(28);
if (lfield.size() > 29)
tmail.field30__c = lfield.get(29);
lTempMail.add(tmail);
return lTempMail;
}
public static void EnvoiMailGenerique(list<TamponMail__c> tmail)
{
//permet d'envoyer tout d'un bloc sans pour autant exploser les limites.
insert tmail;
}
//methode de couverture
static testmethod void testMailTemp()
{
TamponMail__c tmail = new TamponMail__c();
list<string> lmail = new list<string>();
list<string> lfield = new list<string>();
list<TamponMail__c> lTempMail = new list<TamponMail__c>();
string nom;
string objet;
//injecter 40 mails
for (Integer i = 0; i < 40; i++)
lmail.add('MailTest' + i + '@test.com');
//injecter 100 champs customs
for (Integer i = 0; i < 30; i++)
lfield.add('champs custom' + i);
objet = 'test sandbox ';
nom = 'ID_WORKLOW_TEST';
lTempMail = PrepareMailGenerique(lmail, lfield, nom, objet, lTempMail);
EnvoiMailGenerique(lTempMail);
}
//methode de test.
/* public static void EnvoiMailCom()
{
TamponMail__c tmail = new TamponMail__c();
list<string> lmail = new list<string>();
list<string> lfield = new list<string>();
list<TamponMail__c> lTempMail = new list<TamponMail__c>();
string nom;
string objet;
for (Integer i = 0; i < 2000; i++)
{
nom = 'AM_RDV_A_VALIDER';
lmail.add('test@test.com');
objet = 'test sandbox : ' + i;
lfield.add('test description');
lfield.add('12/12/2012 00:00');
PrepareMailGenerique(lmail, lfield, nom, objet, lTempMail);
}
EnvoiMailGenerique(lTempMail);
}*/
} |
Je l'ai testé avec 2000 mails ça passe niquel.
Il se peut qu'il y est quelques exceptions non géré, c'est la version beta :p
Partager