Envoyez des e-mails en masse avec Outlook via une base de données Access

Attention : Programmeurs avertis connaissant un peu Access et Outlook uniquement !

Les listes de distribution disponibles dans Outlook sont une solution, mais pas toujours idéale. Une des limitations de ce procédé est que vous envoyez un seul mail avec dans les zones A, CC ou CCi toutes les adresses de vos correspondants : Il suffit que votre fournisseur d'accès vous interdise par exemple d'envoyer un message à plus de 50 destinataires et que vous en avez 200 pour que vous soyez bloqué.
Avec cette astuce VBA, vous allez pouvoir constourner ce problème en créant un E-Mail par personne. De plus, cette personne sera dans la zone "A:", ce qui va lui donner l'impression que vous avez envoyé ce mail à elle et elle seule ! Vous avez dit puissance ?

Nous allons donc imaginer une base de données Access "Client.mdb", dans laquelle il y a une table "T_Client". Cette table contient 3 champs : NomPrenom, Selectionne (case à cocher) et EMail. Il va s'agir de parcourir une requête "R_ClientSelectionne", et d'envoyer un E-Mail par Client dont le champ Selectionne est à Oui.

Etape 1 : Envoyer un E-Mail en VBA depuis Outlook

Pour commencer, il faut regarder en détail comment une procédure VBA peut créer un message et l'envoyer. Dans Outlook, créez un nouveau Module, et écrivez-y cette première routine :

Sub EnvoiMailSimple()
  ' Création d'une variable de type E-Mail :
  Dim EMail As Object
  ' Assignation de cette variable à la création d'un nouveau Mail :
  Set EMail = Application.CreateItem(olMailItem)
  ' Création de l'e-mail : Titre, Corps du message, destinataire :
  EMail.Subject = "Joli message"
  EMail.Body = "Vive les vacances !"
  EMail.To = "truc@machin.com"
  ' Placement de l'e-mail dans la boîte d'envoi :
  EMail.Send
  ' Libération de la variable-objet :
  Set EMail = Nothing
End Sub

Normalement, après exécution de cette macro, vous devriez retrouver votre message dans votre dossier "Boîte d'envoi"

Etape 2 : exactement la même chose, mais depuis Access

Le code va être le même, mais comme nous pilotons un programme Office (Outlook) depuis un autre (Access), la définition des variables doit être plus pointue. Lancez Access, et créez une nouvelle base de données Client.mdb. N'y créez pour l'instant aucune table, allez directement dans "Modules", et créez un nouveau module.

Une fois dans l'environnement VBA Access, comme nous allons avoir besoin d'utiliser des objets Outlook, il faut qu'on charge la bibliothèque Outlook. Allez dans le menu Outils/Références, et cochez la case "Microsoft Outlook 11.0 object library". le 11.0 veut dire version 2003 : si vous avez XP, c'est 10.0, 2000, c'est 9.0 et 97 c'est évidemment 8.0.

Placez y ce code :

Sub EnvoiMail()
  ' Déclaration d'une variable Application de l'objet Outlook :
  Dim MonOutlook As Object
  Set MonOutlook = Outlook.Application

  Dim EMail As Object
  Set EMail = MonOutlook.CreateItem(olMailItem)
  EMail.To = "haha@hoho.com"
  EMail.Body = "Je suis dans Access"
  EMail.Subject = "Vive Access"
  EMail.Send
  Set EMail = Nothing
End Sub

Constatez qu'il ressemble fortement au code directement exploitable par Oulook que nous avons vu juste avant.

Alors attention, à partir de la version XP (je crois), vous aurez un message "Un programme tente d'envoyer automatiquement du courrier électronique en votre nom, l'autorisez-vous à poursuivre ?". Pour pouvoir répondre Oui, il faut absolument attendre quelques secondes que la barre de progression aie terminé de s'afficher.

La raison en est simple : en effet, comme c'est un programme externe qui tente de créer un e-mail, il se pourrait que ce soit un virus ou un programme malveillant que vous auriez exécuté par mégarde, c'est pourquoi vous devez supporter ce message et son attente. Pourquoi faut il attendre quelques secondes ? simplement xar si un programme virus essayait d'envoyer un e-mail à votre place et cliquer sur OK à votre place, vous n'auriez pas le temps de lire l'avertissement.

Vous pouvez également exécuter ce code même si Outlook est fermé.

Etape 3 : création de la table et de la requête

D'abord la table...

Plus rien à voir avec VBA, maintenant que nous pouvons créler un E-Mail depuis Access, conceptualisons notre table et notre requête. Créez la table suivante :

Nom :
T_Client

Champs:
NomPrenom : Texte
EMail : Texte
Selectionne :Oui/Non

Données :

NomPrenom EMail Selectionne
André Agassi agassi@hotmail.com OUI
Bernard Montiel b.montiel@france.fr OUI
Charles Dumont charles@dumont.com NON
Daniel Muller d_muller@muller.com.au OUI

... et la requête

Créez maintenant une requête basée sur cette table, qui contient les 3 champs, mais qui inclut seulement les "Selectionne". Vous devriez avoir ce résultat :

André Agassi agassi@hotmail.com OUI
Bernard Montiel b.montiel@france.fr OUI
Daniel Muller d_muller@muller.com.au OUI

Enregistrez cette requête sous R_ClientSelectionne

Etape 4 : parcourons la requête en utilisant ADO

Je vous conseille de lire cette page si vous n'êtes pas familier avec ADO.

Rappel de l'utilisation d'ADO

On commence par voir si l'ouverture de la requête se passe bien :

Sub ParcourtRequete()
  ' Déclaraion d'une variable ADO :
  Dim MaBase As New ADODB.Recordset
  ' On ouvre la requête par ADO :
  MaBase.Open "R_ClientSelectionne", CurrentProject.Connection
  ' On se positionne sur le premier enregistrement :
  MaBase.MoveFirst
  ' On affiche le contenu du champs NomPrenom et EMail :
  MsgBox MaBase("NomPrenom")
  MsgBox MaBase("EMail")
  ' On va sur le suivant :
  MaBase.MoveNext
  MsgBox MaBase("NomPrenom")
  ' On ferme proprement et on libère la variable :
  MaBase.Close
  Set MaBase = Nothing
End Sub

Modifions notre code par l'insertion d'une boucle qui va parcourir tous les enregistrements jusqu'à la fin (EOF = End Of File) :

Consultez cette page si vous ne connaissez pas bien l'utilisation de WHILE ... WEND, ou DO ... LOOP

Boucle sur tous les enregistrements

Corrigez le code en conséquence :

Sub ParcourtRequete()
  Dim MaBase As New ADODB.Recordset
  MaBase.Open "R_ClientSelectionne", CurrentProject.Connection
  MaBase.MoveFirst
  ' Tant qu'on est pas sur la fin des enregistrements :
  While Not MaBase.EOF
    MsgBox MaBase("NomPrenom")
    MsgBox MaBase("EMail")
    MaBase.MoveNext
  Wend
  MaBase.Close
  Set MaBase = Nothing
End Sub

Normalement, il devrait vous afficher à l'écran chaque personne avec ensuite son E-Mail, sauf celui dont Selectionne est resté à NON (soit 3 enregistrements X 2 messages = 6 messages)

Etape 5 : mixons les techniques d'accès à Outlook depuis Access avec la boucle ADO

Il ne s'agit donc pas de simplement afficher les enregistrements avec MsgBox, mais de leur envoyer à chacun un E-Mail :

Sub ParcourtRequete()
  Dim MonOutlook As Object
  Dim EMail As Object
  Set MonOutlook = Outlook.Application
  Dim MaBase As New ADODB.Recordset
  MaBase.Open "R_ClientSelectionne", CurrentProject.Connection
  MaBase.MoveFirst
  While Not MaBase.EOF
    Set EMail = MonOutlook.CreateItem(olMailItem)
    EMail.To = MaBase("EMail")
    EMail.Subject = "Déménagement"
    EMail.Body = "Madame, Monsieur, Nous vous informons que nous allons déménager"
    EMail.Send
    MaBase.MoveNext
  Wend
  MaBase.Close
  Set MaBase = Nothing
  Set EMail = Nothing
End Sub

Cette solution fonctionne, mais n'est pas parfaite. En effet, à chaque client, Outlook croit que c'est à chaque fois l'intrusion d'un virus, et impose le message d'attente à chaque fois, ce qui est élvidemment casse-pieds...

Un petit exécutable, que vous trouverez à cette adresse permet d'outrepasser cette limite (je n'ai pas testé)

Pour contourner ça, on pourrait imaginer créer une chaîne de caractère qui se complète gentiment à chaque tour de boucle et qui, à la fin place tous les destinataires d'un seul coup dans le A:; ou le CC, mais si le provider limite le nombre de destinataires simultanés, ça ne va pas non plus... On peut également utiliser EMail.Recipients.Add

Ou alors... Au lieu de faire tourner cette macro depuis Access, la faire tourner depuis le VBA Outlook : comme C'est Outlook lui-même qui crée les messages, on se débarasse de ce message d'attente...

Pour avoir de jolies mises en forme, on peut imposer le format HTML dans le message, comme ceci :
EMail.BodyFormat = olFormatHTML
Mais il faut alors insérer correctement les balises HTML dans :
EMail.Body = "<HTML><strong>Bonjour</strong><BR>Les amis</HTML>"