Mail-Merge to E-mail with Subject personalised by Mail-merge Fields
I know this is impossible, but it can be approximated. The attached code enables you to put character strings like “<<Addressee>>”, rather than real Mail-Merge Fields, in the Subject of a WORD Mail-Merge to E-mail. The routines in the code then change the Subject for each E-mail sent, so that the contents of the column ‘Addressee’ in the Mail-Merge Data Source are substituted for the “<<Addressee>>”.
There is however a severe limitation on its usefulness. The Document has to be saved and re-opened after the code has been added to the Document for it to work. This is because the Document_Open routine has to initialise them_WORDapplication Object that controls the Merge.
Background
For many years we have had an application that creates Excel Mail-Merge Data Sources from data held in an SQL Server Database. The application then draws on a library of WORD Templates changing MacroButtons in the Template into values from the Database. If the E-mail is going to multiple recipients the appropriate Mail-Merge Data Source is attached. Otherwise the Mail-Merge Fields are substituted by the application – thus avoiding the need for a mail-merge.
The Document is then opened in WORD. The user is then left to make any further changes and either send the E-mail or complete the Mail-Merge as normal. Any changes the User makes are captured when the Document closes. The first 255 characters of the Document Body are stored and cross-indexed in the SQL Server Database. The original document is stored in a Windows Folder structure, from where it can be retrieved when needed.
What we now wish to do
So far our application populates the E-mail Envelope with the Subject. However when the User does a Merge to E-mail, the Subject is not transferred to the ‘Merge to E-mail’ Dialog. We would like to find a way of doing so. This is not essential as the User can always copy and paste, but it’s a little inelegant.
When the User clicks OK in this Dialog we then want the WORD Mail-Merge to personalise the Subject line of each E-mail with Fields from the Mail-Merge Data Source – without the need to close and re-open the document.
Progress to Date
So far we have developed the code that actually does the Merge. However it has to be in the Word Document. Can we insert it there from the Access VBA or does it have to be built into the templates to start with? If so how, exactly?
We have tried adding it to the WORD Template, but it does not run – even if we save the document as a
.docm re-open it and enable the Marcos. Even if I copy the VBA for the Project Template into the WORD Document, re-save and re-open it still does not run. I have no idea why not.
We also have to find some other way of initialising the
m_WORDapplication Object, other than in the Document_Open routine. This is because as soon as the WORD Document closes our application thinks the User has finished with the Document and sets about filing it.
Existing Code
'Acknowledgment:
'---------------
' This code is a modified version of that found at:
'
http://www.access-programmers.co.uk/forums/showthread.php?t = 153216
'
' However it has been modified to:
'
' - confirm to our own variable naming and documentation standards,
'
' - All subs have been wrapped with:
' If ActiveDocument.MailMerge.Destination = wdSendToEmail Then
' ......
' End If
' To avoid Errors if user merges to Printer.
'
' - We have changed the replacement delimiters in the .MailSubject from:
' <.....>
' to
' <<.....>>
' as this more nearly represents standard MailMerge Field.
'
' - We explicitly count Mail-Merge DataSource Fields in Document
' i_NumberOfMergeFields = .DataSource.DataFields.Count
' and then use a For...Next loop:
' For i = 1 To i_NumberOfMergeFields
' .....
' Next i
' to control the scanning of:
' ActiveDocument.MailMerge.DataSource.DataFields(i)
' as, in our Application, the most likely candidates for substitution are early on,
' with lower values of i.
'
' - Included an exit from the For...Next loop to save processing.
' 'If there are no Merge-Fields left in .MailSubject Exit For loop
' If InStr(1, .MailSubject, "<<") = 0 Then Exit For
'Declaration of Module Level Variables, which are available throughout this Module
'=================================================================================
Dim WithEvents m_WORDapplication As Application
Dim m_b_WORDapplication_AlreadyOpen As Boolean
Dim m_s_EmailSubject As String
Dim m_b_FirstRecord As Boolean
Private Sub Document_Open()
Set m_WORDapplication = Application
m_b_WORDapplication_AlreadyOpen = True
ThisDocument.MailMerge.ShowWizard 6
End Sub
Private Sub m_WORDapplication_MailMergeBeforeMerge(ByVal Doc As Document, ByVal StartRecord As Long, ByVal EndRecord As Long, Cancel As Boolean)
If ActiveDocument.MailMerge.Destination = wdSendToEmail Thenthe
'Initialise the Module level variable m_b_FirstRecord
'so that Sub m_WORDapplication_MailMergeBeforeRecordMerge will know it 's dealing with the FirstRecord
m_b_FirstRecord = True
End If
End Sub
Private Sub m_WORDapplication_MailMergeBeforeRecordMerge(ByVal Doc As Document, Cancel As Boolean)
'
' Written by: Brian McGuigan
' of: On2it Software Ltd
' Version: 1
' Dated: 26-Mar-14
'First Used in: NEXT Version
' Status: Tested
'
' Purpose: This Subroutine changes the ActiveDocument.MailMerge.MailSubject before each Record is merged.
'
' Method: It does so by replacing any
' ActiveDocument.MailMerge.DataSource.DataFields(i).Name
' it finds in the
' .MailSubject
' delimited by <<.....>> with the corresponding
' .DataSource.DataFields(i).Value
Dim i_NumberOfMergeFields As Integer
Dim i As Integer
With ActiveDocument.MailMerge
If .Destination = wdSendToEmail Then
If m_b_FirstRecord = True Then
'Remember .MailSubject complete with Mail-Merge Fields as originally entered with <<.....>>
m_s_EmailSubject = .MailSubject
m_b_FirstRecord = False
Else
'Reset .MailSubject to so that it still contains the Mail-Merge Fields as entered with <<.....>>
.MailSubject = m_s_EmailSubject
End If
'Count Mail-Merge DataSource Fields in Document
i_NumberOfMergeFields = .DataSource.DataFields.Count
'Replace each Mail-Merge DataSource Field delimited with <<.....>> in .MailSubject
For i = 1 To i_NumberOfMergeFields
.MailSubject = Replace( _
Expression:=.MailSubject, _
Find:="<<" & .DataSource.DataFields(i).Name & ">>", _
Replace:=.DataSource.DataFields(i).Value, _
Compare:=vbTextCompare)
'If there are no Merge-Fields left in .MailSubject Exit For loop
If InStr(1, .MailSubject, "<<") = 0 Then Exit For
Next i
m_b_FirstRecord = False
End If
End With
End Sub
Private Sub m_WORDapplication_MailMergeAfterMerge(ByVal Doc As Document, ByVal DocResult As Document)
ActiveDocument.MailMerge.MailSubject = m_s_EmailSubject
End Sub
Private Sub Document_Close()
If ActiveDocument.MailMerge.Destination = wdSendToEmail Then
Set m_WORDapplication = Nothing
End If
End Sub