Combining Form Fields and Mail Merge

Home Up Search This Site What's New? Audio On CDR Favourites Downloadable files Photo Gallery 2002 Photo Gallery 2003 Photo Gallery 2004/5 Photo Gallery 2006/7 Photo Gallery 2008 Photo Gallery 2009/10 UK Photo Gallery Ireland Photo Gallery Cats Photo Gallery 

 

 

Google
 

 

Many people access the material from this web site daily. Most just take what they want and run. That's OK, provided they are not selling on the material as their own; however if your productivity gains from the material you have used, a donation from the money you have saved, however small, would help to ensure the continued availability of this resource.

Click the appropriate button above to access PayPal.

Combining Mail Merge with Form Fields

 

Protected forms and mail merge are mutually exclusive, but it is possible to combine the two using vba to redefine the document. The following macro code was prepared by fellow MVP Doug Robbins, with a few small refinements of my own, to populate merge fields in a protected form from  Excel and Access data sources.

The third example is potentially even more useful as it can be used with any valid data source. All the examples will work with a form similar to that shown in the illustrations and data sources that contain at least the three fieldnames. The only real proviso is that the third macro looks to the second paragraph on the form (here the Operator field content) to provide the names for the merged documents.

Excel Data Source
  In the example show below, we have a typical protected form to be sent out to a selection of addresses requesting an update of contact details. In the first illustration the form is a protected form attached to an Excel merge data source.

 

When the macro is run, the form is unprotected and the merge fields are replaced with docvariable fields

 

The docvariable fields are populated with the data from each record (below) in turn and each modified document is saved in a folder chosen from the macro.

 

Option Explicit
Dim
xlApp As Object
Di
m xlbook As Object
Dim MergeData As Variant
Dim
MergeFields As Variant
Dim
numrecs As Long, numflds As Long
Dim dSource As String
Dim
qryStr As String
Dim
mfCode As Range
Dim i As Long, j As Long, iCount As Long
Dim Excelwasnotrunning As Boolean
Dim
DocDir As String
Dim
sPassword As String
Dim
fDialog As FileDialog
Sub MailMergeExcelwithFormFields()
With ActiveDocument
     With .MailMerge
          'Check that document is a Letter Type Mail Merge Main Document
          If .MainDocumentType <> wdFormLetters Then
               MsgBox "This application is only designed to be run " & _

               "with a Letter type mail merge main document", _
               vbCritical, "Not the correct type of mail merge document."
               Exit Sub
          End If

          'Check that document has a datasource attached to it
          If Len(.DataSource.name) = 0 Then
               MsgBox "Attach the data source and re-run this macro", _
               vbCritical, "No Data Source!"
               Exit Sub
          End If

          'Check that data source is an Excel spreadsheet
          If Right(.DataSource.name, 4) <> "xlsx" And Right(.DataSource.name, 3) <> "xls" Then
               MsgBox "The data source must be an Excel Spreadsheet.", _
               vbCritical, "Incorrect Data Source Format!"
               Exit Sub
          End If

          'Get the details of the datasource
          With .DataSource
               dSource = .name
               qryStr = .QueryString
               qryStr = Mid(qryStr, InStr(qryStr, "`") + 1)
               qryStr = Left(qryStr, Len(qryStr) - 2)
               numrecs = .RecordCount
               numflds = .FieldNames.Count
          End With
          'Change document to a non-mail merge document
          .MainDocumentType = wdNotAMergeDocument
     End With
     'Select the folder into which the merged documents are to be stored
     Set fDialog = Application.FileDialog(msoFileDialogFolderPicker)
     With fDialog
          .Title = "Select Folder to store the documents and click OK"
          .AllowMultiSelect = False
          .InitialView = msoFileDialogViewList
          If .Show <> -1 Then
               MsgBox "Cancelled By User"
               Exit Sub
          End If

          DocDir = fDialog.SelectedItems.Item(1)
          If Right(DocDir, 1) <> "\" Then DocDir = DocDir + "\"
     End With
     'Unprotect the document
    
sPassword = ""
     If ActiveDocument.ProtectionType <> wdNoProtection Then
          On Error Resume Next
          iCount = 0
OpenPass:
          ActiveDocument.Unprotect Password:=sPassword
          If Err.Number = 5485 Then
               sPassword = InputBox("Enter the password to edit the Form.", _

               "Unprotect Document")
               iCount = iCount + 1

               'Break out of the loop after two incorrect password attempts
               If iCount = 2 Then GoTo NoPass
               GoTo OpenPass
          End If
     End If


     'Convert the MERGEFIELDS to DOCVARIABLE fields
     For i = 1 To .Fields.Count
          If .Fields(i).Type = wdFieldMergeField Then
               Set
mfCode = .Fields(i).Code
               mfCode = Replace(mfCode, "MERGEFIELD", "DOCVARIABLE")
          End If
     Next
i
SavePass:
     If sPassword = "" Then
           sPassword = InputBox("To password protect the forms, enter a password" _

           & vbCr & "or leave blank for no password.", "Protect Documents")
           If sPassword <> "" Then
                If
InputBox("Confirm the password.", "Confirm Password") <> sPassword Then
                     MsgBox "The passwords do not match.", vbCritical + vbOKOnly
                     GoTo SavePass
                End If
           End If
     End If

     'Protect the forms
     .Protect Type:=wdAllowOnlyFormFields, NoReset:=True, Password:=sPassword

     'Access the data source and create an array containing the field names and
     'an array containing all of the data

     On Error Resume Next
     Set xlApp = GetObject(, "Excel.Application")
     If Err Then
          Excelwasnotrunning = True
          Set xlApp = CreateObject("Excel.Application")
     End If
     On Error GoTo
ErrMsg
     With xlApp
          Set xlbook = .Workbooks.Open(dSource)
          MergeData = xlbook.Worksheets(qryStr).Range(.Cells(2, 1), .Cells(1 + numrecs, numflds))
          MergeFields = xlbook.Worksheets(qryStr).Range(.Cells(1, 1), .Cells(1, numflds))
          xlbook.Close SaveChanges:=False
          Set xlbook = Nothing
     End With
     If
Excelwasnotrunning Then xlApp.Quit
     Set xlApp = Nothing
     'Iterate through the records in the datasource
     For j = 1 To numrecs
          'Create variables in the document with the names and values of the fields in each record
          For i = 1 To numflds
               If MergeData(j, i) <> "" Then
                    ActiveDocument.Variables(MergeFields(1, i)).Value = MergeData(j, i)
               Else
                    ActiveDocument.Variables(MergeFields(1, i)).Value = " "
               End If
          Next
i
         'Update the fields in the document
         .Fields.Update
         'Save the document
         .SaveAs DocDir & "MwithFF" & j, AddtoRecentFiles:=False
     Next j
     .Close wdDoNotSaveChanges
End With
'Error Handler
ErrMsg:
If Err.Number > 0 Then
     MsgBox Err.Number & vbCr & Err.Description
     Exit Sub
End If
Exit Sub

NoPass:
MsgBox "The password is incorrect. Unable to complete the process", _
vbCritical, "Wrong password!"
End Sub

 

Access Data Source
 

Sub MailMergefromAccesswithFormFields()

'requires a reference to the Microsoft DAO 3.# Object Library
Dim dSource As String
Dim
qryStr As String
Dim
mfCode As Range
Dim i As Long, j As Long
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim DocDir As String

Dim bProtected As Boolean

Dim sPassword As String
Dim
fDialog As FileDialog
Set fDialog = Application.FileDialog(msoFileDialogFolderPicker)
sPassword = "" 'insert form password, if applicable, between quotes
 

With fDialog
     .Title = "Select Folder to store the documents and click OK"
     .AllowMultiSelect = False
     .InitialView = msoFileDialogViewList
     If .Show <> -1 Then
          MsgBox "Cancelled By User"
          Exit Sub
     End If

     DocDir = fDialog.SelectedItems.Item(1)
     If Right(DocDir, 1) <> "\" Then DocDir = DocDir + "\"
End With

With
ActiveDocument
     'Unprotect the file
     If .ProtectionType <> wdNoProtection Then
          bProtected = True
          .Unprotect Password:=sPassword
     End If
     'Get the details of the datasource
     With .MailMerge.DataSource
          dSource = .name
          qryStr = .QueryString
     End With
     'Convert the MERGEFIELDS to DOCVARIABLE fields
     For i = 1 To .Fields.Count
          If .Fields(i).Type = wdFieldMergeField Then
               Set mfCode = .Fields(i).Code
               mfCode = Replace(mfCode, "MERGEFIELD", "DOCVARIABLE")
          End If
     Next
i
     'Convert the Mail Merge Main document to a normal Word document
     .MailMerge.MainDocumentType = wdNotAMergeDocument
     'Reprotect the form

     If bProtected = True Then
          .Protect _
          Type:=wdAllowOnlyFormFields, _
          NoReset:=True, Password:=sPassword
     End If
End With

' Open the database
Set db = OpenDatabase(dSource)
' Retrieve the recordset
Set rs = db.OpenRecordset(qryStr)
With rs
     ' Move to the first record
     .MoveFirst
     j = 1
     Do While Not .EOF
          'Create variables in the document with the names
          'and values of the fields in each record

          For i = 0 To .Fields.Count - 1
               If .Fields(i).Value <> "" Then
                    ActiveDocument.Variables(.Fields(i).name).Value = _
                    .Fields(i).Value
               End If
          Next
i
          With ActiveDocument
               .Fields.Update
               .SaveAs DocDir & "MwithFF" & j
          End With
          .MoveNext
          j = j + 1
     Loop
End With

rs.Close
db.Close
Set rs = Nothing
Set db = Nothing
End Sub
 

Any Data Source
 

Sub MergefromAnyDataSourcewithFormFields()
Dim i As Long
Dim oDoc As Document
Dim DocName As String
Dim
oRng As Range
Dim sPassword As String
Dim
bProtected As Boolean
Dim fDialog As FileDialog
Dim bAddin As Boolean
Dim
sAddin As String
bAddin = False
sAddin = Options.DefaultFilePath(wdStartupPath) _
& Chr(92) & "MMtoDocs*.dotm"
'Check if the splitmerge add-in is installed
On Error GoTo ErrorHandler
If AddIns(sAddin).Installed = True Then
     bAddin = True
     'and if it is turn it off
     AddIns(sAddin).Installed = False
End If
Folder:
'Pick a folder to save the files
Set fDialog = Application.FileDialog(msoFileDialogFolderPicker)
sPassword = "" 'insert form password, if applicable, between quotes
With fDialog
     .Title = "Select Folder to store the documents and click OK"
     .AllowMultiSelect = False
     .InitialView = msoFileDialogViewList
     If .Show <> -1 Then
          MsgBox "Cancelled By User"
          Exit Sub
     End If

     DocDir = fDialog.SelectedItems.Item(1)
     If Right(DocDir, 1) <> "\" Then DocDir = DocDir + "\"
End With

Set oDoc = ActiveDocument
With oDoc
    'Unprotect the file
     If .ProtectionType <> wdNoProtection Then
          bProtected = True
          .Unprotect Password:=sPassword
     End If

     For i = .FormFields.Count To 1 Step -1
          If .FormFields(i).Type = wdFieldFormTextInput Then
               .FormFields(i).Range.Text = "FF" & i
          End If
     Next
i
     With .MailMerge
          .Destination = wdSendToNewDocument
          .Execute
     End With
End With

oDoc.Close wdDoNotSaveChanges
Selection.HomeKey wdStory
With Selection.Find
     Do While .Execute(findText:="FF[0-9]{1,}", _
              Forward:=True, _
              MatchWildcards:=True, _
              Wrap:=wdFindStop, _
              MatchCase:=True) = True
     ActiveDocument.FormFields.Add _
              Selection.Range, _
              wdFieldFormTextInput
     Loop
End With
'Now split the document
Selection.EndKey Unit:=wdStory
Letters = Selection.Information(wdActiveEndSectionNumber)
Selection.HomeKey Unit:=wdStory
Counter = 1
While Counter < Letters
     ActiveDocument.Sections.First.Range.Cut
     Documents.Add
     'Documents are based on the Normal template
     'To use an alternative template follow the link.

     With Selection
          .Paste
          .EndKey Unit:=wdStory
          .MoveLeft Unit:=wdCharacter, Count:=1
          .Delete Unit:=wdCharacter, Count:=1
     End With
     'locate the position of the data in the document to
     'be used as a filename
- here the 'Operator' in the
     'second paragraph

     Set oRng = ActiveDocument.Paragraphs(2).Range
     'remove the paragraph mark from the end of the range
     oRng.End = oRng.End - 1
     'Set the path and name of the document
     DocName = DocDir & oRng.Text
     'Protect the document for forms
     ActiveDocument.Protect _
            Type:=wdAllowOnlyFormFields, _
            NoReset:=True, Password:=sPassword
     'and save it
     ActiveDocument.SaveAs FileName:=DocName, _
            FileFormat:=wdFormatDocument, _
            AddToRecentFiles:=False
     ActiveWindow.Close
     Counter = Counter + 1
Wend
'If the splitmerge add-in was turned off earlier
'turn it on again

If bAddin = True Then
     AddIns(sAddin).Installed = True
End If
'close the now empty merged document without saving
ActiveDocument.Close wdDoNotSaveChanges
End
ErrorHandler:
If Err.Number = 5941 Then GoTo Folder
End Sub