Piloter un publipostage Word depuis Access

Denis Hulo

Objectif : apprendre à piloter une fusion-publipostage Word depuis Access.

Niveau requis : avancé.

Commentez cet article : Commentez

- Titre : Piloter un publipostage Word depuis Access

- Auteur : Denis Hulo

- Parution : 30 mars 2021

- Public visé :

- Licence : Copyright ® 2021 Denis Hulo. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Introduction

- II. Liaison entre le document de fusion et la source de données

- III. Piloter un publipostage depuis Access

- III-A. Utilisation d'une gestion d'erreur

- III-B. Déclaration des variables objet en début de code

- III-C. Ouverture du document de fusion Word

- III-D. Paramétrage et exécution du publipostage

- III-E. Libération des variables objet en fin de procédure

- III-F. Code complet

- IV. Résultat de la fusion

- V. Pour aller plus loin : envoi de documents individuels par e-mail

- VI. Le dossier à télécharger

- VII. Remerciements

I - Introduction

C'est bien connu, Word permet de réaliser des documents avec une mise en page de meilleure qualité qu'Access. C'est pourquoi, il peut-être intéressant de réaliser ses documents avec Word, puis de les lier à une source Access en vue de piloter par la suite un publipostage depuis Access, plutôt que de créer des états Access.

Principe du publipostage avec Word

Publipostage avec Word

Pour réaliser ce publipostage, on va devoir piloter Word depuis Access en utilisant du code VBA et la fonctionnalité MailMerge de Word, mais ce faisant, on peut rencontrer des problèmes de lenteur, d'application ou de processus déjà chargé en mémoire, avec comme conséquence une procédure qui ne finit pas, ou carrément un plantage de l'application.

Sans compter les problèmes de droits d'accès à la base de données reliée au document de fusion avec un message du genre :

« La base de données a été placée par l'utilisateur "Utilisateur" sur "Ordinateur" dans un état l'empêchant d'être ouverte ou verrouillée ».

On va donc décrire par la suite les différentes parties du code nécessaires pour bien piloter ce publipostage Word :

- Utilisation d'une gestion d'erreur

- Déclaration des variables objet en début de code

- Ouverture du document de fusion Word

- Paramétrage et exécution du publipostage

- Libération des variables objet en fin de procédure

II - Liaison entre le document de fusion et la source de données

On suppose ici que le document de fusion est déjà relié dans Word à une source de données (table Access) et que les champs de fusion ont déjà été insérés dans le document :

1. Sélection de la source de données : la base de données BD_Destinataires.accdb et la table source T_Destinataire ;

2. Insertion des champs de fusion : « NomDestinataire », « PrenomDestinataire »…

Liaison document Word / source de données

Nous expliquerons par la suite comment appliquer un filtre dynamique sur la source de données, pour ne garder par exemple que les destinataires habitant la ville de Bordeaux.

Si la source de données du document de fusion est le fichier Access permettant de piloter Word, et si, en particulier, vous êtes en phase de test (ouverture de la base en mode exclusif, module ou formulaire en cours de modification…), vous pouvez avoir au moment de lancer le publipostage, un message d'erreur indiquant que la base de données est déjà ouverte par un autre utilisateur :

erreur de droit d'accès à la base

C'est pourquoi, pour éliminer les possibilités de création de situations de verrouillage de la base, il est préférable que le fichier permettant de lancer le publipostage ne soit pas relié au document de fusion.

En mode multiutilisateur, optez bien sûr pour une architecture Frontale/Dorsale, le document de fusion étant relié au fichier contenant les données situé sur le serveur.

Pour mieux comprendre comment créer au préalable cette liaison et plus encore, je vous invite à consulter Fusion et Publipostage, par l'interface et en VBA par Olivier Lebeau.

III - Piloter un publipostage depuis Access

Décrivons dans cette section les parties importantes du code VBA permettant d'exécuter ce publipostage.

III-A - Utilisation d'une gestion d'erreur

Elle va permettre en particulier de libérer la mémoire en cas d'erreur :

On Error GoTo err_LancerFusionPublipostage
...
...
err_LancerFusionPublipostage:
If Err.Number <> 0 Then ' si une erreur s'est produite
MsgBox (Err.Description) ' affiche une description de l'erreur
End If
' On libère les variables objet ici

III-B - Déclaration des variables objet en début de code

L'utilisation de variables objet à liaison anticipée (early binding), c'est-à-dire déclarées dans un type d'objet spécifique, offre plusieurs avantages :

les objets à liaison anticipée permettent au compilateur d’allouer de la mémoire et d’effectuer d’autres optimisations avant l’exécution d'une application. Ils sont donc plus rapides que les objets à liaison tardive ;

l'utilisation du early binding rend également votre code plus lisible et facilite sa gestion. En effet, cette solution permet d'afficher les membres (propriétés, méthodes…) de vos objets au fur et à mesure de l'écriture de votre code (complétion - CTRL + Espace), et vous donne accès à l'aide dynamique sur la syntaxe.

Dim wdApp As Word.Application ' variable objet pour faire référence à l'application Word
Dim wdDoc As Word.Document ' variable objet pour faire référence au document Word
'...

Pour avoir plus d'informations sur le sujet, je vous invite à consulter Early ou Late Binding par Maxence Hubiche.

III-C - Ouverture du document de fusion Word

Pour ouvrir le document Word, on a besoin, avant, de créer un objet application Word.

Mais pour cela, il faut bien vérifier si un objet de ce type n'est pas déjà chargé en mémoire :

On Error Resume Next ' instruction pour ignorer l'erreur qui pourrait se déclencher sur la ligne suivante
Set wdApp = GetObject(, "Word.Application") ' on récupère l'instance Word ouverte : si pas d'instance la variable est à nothing
On Error GoTo err_LancerFusionPublipostage ' reprend la gestion d'erreur normale en annulant l'effet de l'instruction On error resume next
If wdApp Is Nothing Then ' si pas d'instance de Word de créée
Set wdApp = CreateObject("Word.Application") ' on crée une nouvelle instance
End If
...

Puis, on ouvre le document de fusion :

Set wdDoc = wdApp.Documents.Open(cheminDocument) ' ouverture du document de fusion

III-D - Paramétrage et exécution du publipostage

Avant d'exécuter la fusion-publipostage, on doit bien sûr indiquer dans le code la source de données et la destination du publipostage (nouveau document, imprimante, e-mail…).

Pour paramétrer et exécuter ce publipostage, on utilise la propriété MailMerge du document, qui renvoie un objet MailMerge représentant la fonctionnalité de fusion et de publipostage pour le document spécifié :

With wdDoc.MailMerge

' Sélectionne la base de données et la chaine SQL comme source de données pour la fusion
.OpenDataSource Name:=chemindb, SQLStatement:=chaineSQL

' Indique la destination du publipostage. Ce peut être un nouveau document, une imprimante, un e-mail ou un FAX
.Destination = wdSendToNewDocument ' ici la destination est un nouveau document

' Exécute la fusion dans Word
.Execute
End With

La chaine SQL affectée à l'argument SQLStatement de la méthode OpenDataSource, permet d'appliquer un filtre sur les données des destinataires avant la fusion. Si on souhaite par exemple ne garder que les destinataires habitant Bordeaux :

chaineSQL = "select * from [T_Destinataire] where Ville like ""Bordeaux"""

Si vous souhaitez avoir plus d'informations sur le sujet, je vous invite à consulter Fusion et Publipostage, par l'interface et en VBA

III-E - Libération des variables objet en fin de procédure

Pour libérer la mémoire et éviter de se retrouver avec des processus « fantômes », il faut impérativement mettre ces variables à nothing :

' on libère les variables objet
Set wdDoc = Nothing
Set wdApp = Nothing

III-F - Code complet

La fonction LancerPublipostage permet d'exécuter la fusion-publipostage depuis Access.

Arguments :

- cheminDocument : chemin du document de fusion ;

- cheminDB : chemin de la base de données source du document ;

- chaineSQL : chaineSQL permettant de filtrer les données sources du document de fusion.

Fonction LancerFusionPublipostage

Function lancerPublipostage(ByVal cheminDocument As String, ByVal chemindb As String, ByVal chaineSQL As String) As Boolean
On Error GoTo err_lancerPublipostage
Dim wdApp As Word.Application ' variable objet pour faire référence à l'application Word
Dim wdDoc As Word.Document ' variable objet pour faire référence au document Word
Dim nbEnrgs As Long

On Error Resume Next ' instruction pour ignorer l'erreur qui pourrait se déclencher sur la ligne suivante
Set wdApp = GetObject(, "Word.Application") ' on récupère l'instance Word ouverte : si pas d'instance la variable est à nothing
On Error GoTo err_lancerPublipostage ' reprend la gestion d'erreur normale en annulant l'effet de l'instruction On error resume next
If wdApp Is Nothing Then ' si pas d'instance de Word de créée
Set wdApp = CreateObject("Word.Application") ' on crée une nouvelle instance de l'application Word
End If

Set wdDoc = wdApp.Documents.Open(cheminDocument) ' on ouvre le document de fusion

' Rend Word visible important puisque la fusion se fait à l'écran.
wdApp.Application.Visible = True

With wdDoc.MailMerge

' Sélectionne la base de données et la chaine SQL comme source de données pour la fusion
.OpenDataSource Name:=chemindb, SQLStatement:=chaineSQL

' Indique la destination du publipostage. Ce peut être un nouveau document, une imprimante, un e-mail ou un FAX
.Destination = wdSendToNewDocument ' ici la destination est un nouveau document

' Exécute la fusion dans Word
.Execute

End With
wdDoc.Close (False) ' ferme le document de fusion sans l'enregistrer
lancerPublipostage = True ' indique que le publipostage s'est bien déroulé
err_lancerPublipostage: ' gestion d'erreur
If Err.Number <> 0 Then ' si une erreur s'est produite
MsgBox (Err.Description) ' affiche le message d'erreur
End If
On Error Resume Next
' on libère les variables objet
Set wdDoc = Nothing
Set wdApp = Nothing
End Function

On lance la fusion-publipostage simplement en passant à la fonction les bons arguments :

Private Sub CmdFusionPublipostage_Click()
Dim chemindocument As String
Dim chemindb As String
Dim chaineSQL As String
chemindocument = CurrentProject.Path & "\Documents\Document_Fusion.docx" ' définit le chemin du document de fusion
chemindb = CurrentProject.Path & "\Base\BD_Destinataires.accdb" ' définit le chemin de la base de données source du document de fusion
' définit le chaîne SQL pour la source du document, elle permet d'appliquer un filtre de façon dynamique
If Me.txtVille = "[Toutes]" Then
chaineSQL = "select * from [T_Destinataire]"
Else
chaineSQL = "select * from [T_Destinataire] where Ville like """ & Me.txtVille & """"
End If
If lancerFusionPublipostage(chemindocument, chemindb, chaineSQL) Then
MsgBox "Publipostage réalisé avec succès !", vbExclamation
Else
MsgBox "Une erreur a eu lieu au cours de la procédure !", vbExclamation
End If
End Sub

IV - Résultat de la fusion

On lance le publipostage depuis un formulaire Access :

Formulaire Fusion et publipostage

Résultat de la fusion dans Word :

Résultat de la fusion

On constate que le document final comporte autant de lettres types qu'il y a de destinataires sélectionnés dans Access.

V - Pour aller plus loin : envoi de documents individuels par e-mail

Voici un exemple de pilotage d'un envoi de documents individuels depuis Access.

Déroulé de la fonction :

1. Ouverture du document de fusion ;

2. Filtre de la source de données en fonction de la ville choisie ;

3. Parcours des enregistrements de la source de données ;

4. Pour chaque destinataire, génération, enregistrement et envoi par e-mail de son document individuel.

Pour la partie publipostage, on filtre comme auparavant la source de données du document de fusion, à l'aide de l'argument SQLStatment de la méthode OpenDataSource :

With wdDoc.MailMerge

' Sélectionne la base de données et la chaine SQL comme source de données pour la fusion
.OpenDataSource Name:=chemindb, SQLStatement:=chaineSQL
.Destination = wdSendToNewDocument ' ici la destination est un nouveau document
...

Puis, on parcourt les enregistrements contenus dans la source de données du document, et pour chaque destinataire, on génère son document avant de l'envoyer par e-mail :

For idEnrg = 1 To nbEnrgs

.DataSource.FirstRecord = .DataSource.ActiveRecord ' enregistrement actif
.DataSource.LastRecord = .DataSource.ActiveRecord ' enregistrement actif

email = .DataSource.DataFields("Email").Value ' récupère dans une variable l'adresse e-mail contenu dans l'enregistrement courant

' Exécute la fusion dans Word
.Execute

With wdApp.ActiveDocument ' référence au document actif

cheminDoc = CurrentProject.Path & "\Documents\document_invitation.pdf"
.SaveAs2 cheminDoc, wdFormatPDF ' enregistre le document actif au format pdf en vu de l'envoyer
Call EnvoiEmail(olApp, cheminDoc, email, ObjetMessage, Message)
.Close (False) ' ferme le documennt actif

End With

.DataSource.ActiveRecord = wdNextRecord ' on passe au prochain enregistrement

Next idEnrg
...

Code comple de la fonction :

fonction lancerPublipostageEmail

Function lancerPublipostageEmail(ByVal cheminDocument As String, ByVal chemindb As String, ByVal chaineSQL As String, ByVal ObjetMessage As String, ByVal Message As String) As Boolean
'On Error GoTo err_lancerPublipostageEmail
Dim wdApp As Word.Application ' variable objet pour faire référence à l'application Word
Dim wdDoc As Word.Document ' variable objet pour faire référence au document Word
Dim olApp As Object ' variable objet pour faire référence à l'application Outlook
Dim nbEnrgs As Long, idEnrg As Long
Dim cheminDoc As String
Dim email As String ' variable pour enregistrer l'adresse e-mail des destinataires

On Error Resume Next ' instruction pour ignorer l'erreur qui pourrait se déclencher sur la ligne suivante
Set wdApp = GetObject(, "Word.Application") ' on récupère l'instance Word ouverte : si pas d'instance la variable est à nothing
On Error GoTo err_lancerPublipostageEmail ' reprend la gestion d'erreur normale en annulant l'effet de l'instruction On error resume next
If wdApp Is Nothing Then ' si pas d'instance de Word de créée
Set wdApp = CreateObject("Word.Application") ' on crée une nouvelle instance
End If

Set wdDoc = wdApp.Documents.Open(cheminDocument) ' on ouvre le document Word

' Rend Word visible : important puisque la fusion se fait à l'écran.
wdApp.Application.Visible = True

'On crée l'objet Application Outlook
On Error Resume Next ' instruction pour ignorer l'erreur qui pourrait se déclencher sur la ligne suivante
Set olApp = GetObject(, "Outlook.Application") ' on récupère l'instance Word ouverte : si pas d'instance la variable est à nothing
On Error GoTo err_lancerPublipostageEmail ' reprend la gestion d'erreur normale en annulant l'effet de l'instruction On error resume next
If olApp Is Nothing Then ' si pas d'instance de Outlook de créée
RunOutlook ' on ouvre l'application Outlook
Set olApp = CreateObject("Outlook.Application") ' on crée une nouvelle instance
End If

With wdDoc.MailMerge

' Sélectionne la base de données et la chaine SQL comme source de données pour la fusion
.OpenDataSource Name:=chemindb, SQLStatement:=chaineSQL
.Destination = wdSendToNewDocument ' ici la destination est un nouveau document

.DataSource.ActiveRecord = wdLastRecord ' on se déplace sur le dernier enregistrement pour les compter
nbEnrgs = .DataSource.ActiveRecord ' nombre d'enregistrements de la source de données
.DataSource.ActiveRecord = wdFirstRecord ' on revient sur le 1er enregistrement

For idEnrg = 1 To nbEnrgs

.DataSource.FirstRecord = .DataSource.ActiveRecord ' enregistrement actif
.DataSource.LastRecord = .DataSource.ActiveRecord ' enregistrement actif

email = .DataSource.DataFields("Email").Value ' récupère dans une variable l'adresse e-mail contenu dans l'enregistrement courant

' Exécute la fusion dans Word
.Execute

With wdApp.ActiveDocument ' référence au document actif

cheminDoc = CurrentProject.Path & "\Documents\document_invitation.pdf"
.SaveAs2 cheminDoc, wdFormatPDF ' enregistre le document actif au format pdf en vu de l'envoyer
Call EnvoiEmail(olApp, cheminDoc, email, ObjetMessage, Message)
.Close (False) ' ferme le documennt actif

End With

.DataSource.ActiveRecord = wdNextRecord ' on passe au prochain enregistrement

Next idEnrg

End With

wdDoc.Close (False) ' ferme le document de fusion sans l'enregistrer

wdApp.Quit ' ferme l'application Word

lancerPublipostageEmail = True ' indique que le publipostage s'est bien déroulé

err_lancerPublipostageEmail: ' gestion d'erreur
If Err.Number <> 0 Then ' si une erreur s'est produite
MsgBox (Err.Description) ' affiche le message d'erreur
End If

On Error Resume Next
' on libère les variables objet
Set olApp = Nothing
Set wdDoc = Nothing
Set wdApp = Nothing

End Function

On lance l'envoi des documents individuels aux destinataires depuis le formulaire Access, après avoir choisi comme destination « E-mails » :

Formulaire Fusion et publipostage

Vous retrouverez le code complet de la fonction dans le fichier disponible en téléchargement.

Pour aller encore plus loin, je vous invite à consulter Émettre et archiver des documents types et Gérer une association avec Access par Claude Leloup.

VI - Le dossier à télécharger

Le dossier complet contient le document de fusion et les fichiers Access.

Ouvrir le fichier fusion-publipostage-word v1.1.accdb, puis rétablir au démarrage le lien avec la base BD_Destinataires.accdb située dans le dossier Base.

VII - Remerciements

Je tiens à remercier Pierre Fauconnier et zoom61 pour m'avoir conseillé et aidé pour la réalisation de cet article, ainsi que Claude Leloup pour sa relecture.