Mailmerge from Excel using Word template VBA - vba

I have created a Userform where you can flag records as "In Progress", "Completed", and "Not Completed".
This will reflect on the sheet as below:
Records marked as "In Progress" will have the letter "P" in the status column.
Records marked as "Completed" will have the letter "Y" in the status column.
Records marked as "Not Completed" will have the letter "N" in the status column.
DataSheet http://im39.gulfup.com/VZVxr.png!
I want to run a mailmerge using the below buttons on the user form:
Userform http://im39.gulfup.com/98isU.png!
I have created this work template for the fields.
Document http://im39.gulfup.com/4WMLh.png!
This word template file called "MyTemplate" will be in the same directory as the excel file.
I am trying to figure out how:
(1) Select recepients by filtering the "Status" column, so if the user pressed the first button, it will run the mail merge only for records with "P" in the status column.
(2) Run mailmerge without displaying Microsoft Word and only displaying the "Save As" dialog where the user can select where to save the file.
(3) This file should be saved in PDF format.
I am running Office 2013 and so far I have the code in bits and pieces and had no luck when trying to run it.
I have uploaded the data I am trying to work on:
MyBook: https://db.tt/0rLUZGC0
MyTemplate: https://db.tt/qPuoZ0D6
Any help will be highly appreciated.
Thanks.

(1) What I use is the WHERE clause (on the OpenDataSource, you probably don't need all those options)
' setup the SQL
Dim sSQLModel As String, sSQLWhere As String
sSQLModel = " Where ( AssignLtrType = 'T1' or AssignLtrType = 'T2' ) ;"
' replace the appropriate value(s)
sSQLWhere = sSQLModel ' never replace in the model
sSQLWhere = Replace(sSQLWhere, "T1", mydatavariable)
' open the MERGE
doc.MailMerge.OpenDataSource Name:=sIn, _
ConfirmConversions:=False, readOnly:=False, LinkToSource:=True, _
AddToRecentFiles:=False, PasswordDocument:="", PasswordTemplate:="", _
WritePasswordDocument:="", WritePasswordTemplate:="", Revert:=False, _
Format:=wdOpenFormatAuto, Connection:= _
"Provider=Microsoft.Jet.OLEDB.4.0;Password="""";" & _
"User ID=Admin;" & _
"Data Source=" & sXLSPathFile & ";" & _
"Mode=Read;Extended Properties=" & _
"HDR=YES;IMEX=1;"";Jet OLEDB:System database="""";" _
, SQLStatement:="SELECT * FROM `Detail$`", _
SQLStatement1:=sSQLWhere, _
SubType:=wdMergeSubTypeAccess
' do the MERGE
With doc.MailMerge
.Destination = wdSendToPrinter
.SuppressBlankLines = True
With .DataSource
.FirstRecord = wdDefaultFirstRecord
.LastRecord = wdDefaultLastRecord
End With
.Execute Pause:=False
End With
(2) Prior to the above, make the doc Visible (or Invisible)
' setup the template document
Dim doc As Word.Document
Set doc = wrdApp.Documents.Add(sPathFileTemplate)
wrdApp.Visible = True ' you can say False
(3) I have Adobe PDF as a Printer (the registry routines were from the web--Google them). Put this prior to OpenDataSource.
' Get current default printer.
SetDefaultPrinter "Adobe PDF"
'Create the Registry Key where Acrobat looks for a file name
CreateNewRegistryKey HKEY_CURRENT_USER, _
"Software\Adobe\Acrobat Distiller\PrinterJobControl"
'Put the output filename where Acrobat could find it
SetRegistryValue HKEY_CURRENT_USER, _
"Software\Adobe\Acrobat Distiller\PrinterJobControl", _
wrdApp.Application.Path & "\WINWORD.EXE", sPathFilePDF
In the SQL, change the tab name from Detail$ to yourTab$ (needs trailing $)
added later--
Dim sIn As String
sIn = SelectAFile(sInitial:=sDriveSAO, sTitle:=" XLS file")
If (sIn = "" Or sIn = "False") Then Exit Sub
and Google for SelectAFile
added 1/22 aft
' ============= added ===========
Dim xls As Excel.Application ' for me, because I am running in MSAccess as mdb
Set xls = New Excel.Application
Dim wrdApp As Word.Application ' for you, to have WORD running
Set wrdApp = New Word.Application
Dim sPathFileTemplate As String
sPathFileTemplate = xls.GetOpenFilename(" docx file,*.docx", , "Template file")
' ============= added ===========
' changed you only need one variable
sSQLModel = " Where ( Status = 'T1' ) ;"
' changed replace, possibly with some screen value
sSQLWhere = Replace(sSQLWhere, "T1", "P")
' changed because your tab is named Sheet1
, SQLStatement:="SELECT * FROM `Sheet1$`", _
' ============= added ===========
doc.Close False
Set doc = Nothing
wrdApp.Quit False
Set wrdApp = Nothing
' ============= added ===========

OK so with a lot of help from #donPablo I finally got a working code which does exactly what I want.
BTW the "Status" in sSQLModel = " Where ( Status = 'T1' ) ;" can be change to any other column heading, but in my case I am filtering based on a value in the column F (Status).
The "P" in sSQLWhere = Replace(sSQLWhere, "T1", "P") can also be change to the value been filtered on, but in my case I want all the records containing "P" in the "Status" column.
The "Sheet1" in , SQLStatement:="SELECT * FROMSheet1$", _ can be changed to the name of the sheet containing the source data for the merge. (Don't forget to include the $ sign at the end of the sheet name.
Before proceeding make sure to load the Microsoft Word Object Library (VBA - Tools - References)
And here is the working code:
Private Sub CommandButton1_Click()
Dim xls As Excel.Application
Set xls = New Excel.Application
Dim wrdApp As Word.Application
Set wrdApp = New Word.Application
Dim sPathFileTemplate As String
sPathFileTemplate = ThisWorkbook.Path & "\MyTemplate.docx" 'This gets the file called MyTemplate from the same directory
'in which this excel file is running from
' setup the template document
Dim doc As Word.Document
Set doc = wrdApp.Documents.Add(sPathFileTemplate)
wrdApp.Visible = False ' Make MS Word Invisible
Dim sIn As String
sIn = ThisWorkbook.FullName 'This Workbook is set the merge data source
' setup the SQL
Dim sSQLModel As String, sSQLWhere As String
sSQLModel = " Where ( Status = 'T1' ) ;"
' replace the appropriate value(s)
sSQLWhere = sSQLModel
sSQLWhere = Replace(sSQLWhere, "T1", "P")
' open the MERGE
doc.MailMerge.OpenDataSource Name:=sIn, _
ConfirmConversions:=False, ReadOnly:=False, LinkToSource:=True, _
AddToRecentFiles:=False, PasswordDocument:="", PasswordTemplate:="", _
WritePasswordDocument:="", WritePasswordTemplate:="", Revert:=False, _
Format:=wdOpenFormatAuto, Connection:= _
"Provider=Microsoft.Jet.OLEDB.4.0;Password="""";" & _
"User ID=Admin;" & _
"Data Source=" & sXLSPathFile & ";" & _
"Mode=Read;Extended Properties=" & _
"HDR=YES;IMEX=1;"";Jet OLEDB:System database="""";" _
, SQLStatement:="SELECT * FROM `Sheet1$`", _
SQLStatement1:=sSQLWhere, _
SubType:=wdMergeSubTypeAccess
' do the MERGE
With doc.MailMerge
.Destination = wdSendToNewDocument
.SuppressBlankLines = True
With .DataSource
.FirstRecord = wdDefaultFirstRecord
.LastRecord = wdDefaultLastRecord
End With
.Execute Pause:=False
End With
'If you want you can delete this part and proceed to diretly define the
'filename and path below in "OutputFileName"
On Error Resume Next
Dim FileSelected As String
FileSelected = Application.GetSaveAsFilename(InitialFileName:="Export", _
FileFilter:="PDF Files (*.pdf), *.pdf", _
Title:="Save PDF as")
If Not FileSelected <> "False" Then
MsgBox "You have cancelled"
doc.Close False
Set doc = Nothing
wrdApp.Quit False
Set wrdApp = Nothing
Exit Sub
End If
If FileSelected <> "False" Then
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
wrdApp.Application.Options.SaveInterval = False
'Saves Documents as PDF and does not open after saving, you can change OpenAfterExport:=False to True
wrdApp.Application.ActiveDocument.ExportAsFixedFormat OutputFileName:=FileSelected, _
ExportFormat:=wdExportFormatPDF, OpenAfterExport:=False, OptimizeFor:=wdExportOptimizeForPrint, _
Range:=wdExportAllDocument, FROM:=1, To:=1, Item:=wdExportDocumentContent, IncludeDocProps:=True, _
KeepIRM:=True, CreateBookmarks:=wdExportCreateNoBookmarks, DocStructureTags:=True, _
BitmapMissingFonts:=True, UseISO19005_1:=False
doc.Close False
Set doc = Nothing
wrdApp.Quit False
Set wrdApp = Nothing
MsgBox "Done"
End If ' this EndIf pretains to the SaveAs code above
End Sub
I cannot stress enough how much help was #donPablo, thanks again, you just made my weekend and I am selecting your answer as accepted :)

Related

Mail Merge vb.net

I'm using mail merge function to merge data from excel sheets to word letter. and I use the following connection and command.
Sub WriteInWord()
Dim WdApp As Object
Dim WdDoc As Object
result = Path.GetFileName(TextBox1.Text)
Dim BatchNumber = Mid(result, 18, 5)
WdApp = CreateObject("Word.Application")
WdDoc = CreateObject("Word.Document")
WdDoc = WdApp.Documents.Open(TextBox2.Text, ConfirmConversions:=
False, ReadOnly:=False, AddToRecentFiles:=False, PasswordDocument:="",
PasswordTemplate:="", Revert:=False, WritePasswordDocument:="",
WritePasswordTemplate:="", XMLTransform:="")
WdDoc.MailMerge.OpenDataSource(Name:=TextBox1.Text,
ConfirmConversions:=False, ReadOnly:=False, LinkToSource:=True,
AddToRecentFiles:=False, PasswordDocument:="", PasswordTemplate:="",
WritePasswordDocument:="", WritePasswordTemplate:="", Revert:=False, Connection:=
"Provider=Microsoft.ACE.OLEDB.12.0;User ID=Admin; Mode=Read; Extended Properties=""HDR=YES;IMEX=1;"";Jet OLEDB:System database=""""; Jet OLEDB:Registry Path="""";Jet OLEDB:Engine Type=35;Jet OLEDB:Database Locking Mode=0; Jet OLEDB:Global", SQLStatement:="SELECT * FROM `Sheet1$`", SQLStatement1:="")
' .Destination 0 = DOCUMENT, 1 = PRINTER
WdApp.ActiveDocument.MailMerge.Destination = 0 'wdSendToNewDocument
WdApp.ActiveDocument.MailMerge.SuppressBlankLines = True
With WdApp.ActiveDocument.MailMerge.DataSource
.FirstRecord = 1 'wdDefaultFirstRecord
.LastRecord = -16 'wdDefaultLastRecord
End With
WdApp.ActiveDocument.MailMerge.Execute(Pause:=False)
WdDoc.Close(savechanges:=False) 'Close the original mail-merge template file.
Dim outputFilename As String = Path.ChangeExtension(inputFilePath + "\" + BatchNumber + ".docx", "pdf")
Dim fileFormat As Object = WdSaveFormat.wdFormatPDF
WdApp.ActiveDocument.SaveAs(outputFilename, fileFormat)
WdApp.Quit()
WdDoc = Nothing
WdApp = Nothing
MsgBox("FINISHED WITH MERGE")
End Sub
the excel value is this
Merged value from excel to word is this
As you can see, the value from excel to word has changed. How can I fix this? Thank you.
Thanks for the inspiration.
I know where's my problem. I changed the SQL statement from
SQLStatement:="SELECT * FROM `Sheet1$`"
To
SQLStatement:="SELECT * FROM `SheetName$`"
The "SheetName" is excel sheet name, because my spreadsheet has a name.

Is it possible to mail merge individual records instead of having all records in one document?

The code given below takes all records and combines them into 1 mail merged document. I tried modifying the code itself to try to mail merge individual documents for each record.
However, it only gives out an error which is the "Object variable or With block variable not set". My suspicion is because the records taken using the SQL statement grabs the entire existing records in the database.
Is it possible to somehow only mail merge and save as individual documents for each record?
Example:
The records of Record 1 = Record1.docx
The records of Record 2 = Record2.docx
The records of Record 3 = Record3.docx
Sub startMergeAL()
Dim oWord As Object, oWdoc As Object
Dim wdInputName As String, wdOutputName As String, outFileName As String
'Temporary variables
Dim totalRecord As Long, recordNumber As Long
'------------------------------------------------
' Set Template Path
'------------------------------------------------
wdInputName = CurrentProject.Path & "\Acceptance form V3.docx"
'------------------------------------------------
' Create unique save filename with minutes
' and seconds to prevent overwrite
'------------------------------------------------
outFileName = "Acceptance Letter - " & Format(Now(), "yyyymmddmms")
'------------------------------------------------
' Output File Path w/outFileName
'------------------------------------------------
wdOutputName = CurrentProject.Path & "\Results\" & outFileName
Set oWord = CreateObject("Word.Application")
Set oWdoc = oWord.Documents.Open(wdInputName)
'------------------------------------------------
' Start mail merge
'------------------------------------------------
With oWdoc.MailMerge
.MainDocumentType = 0 'wdFormLetters
.OpenDataSource _
Name:=CurrentProject.FullName, _
AddToRecentFiles:=False, _
LinkToSource:=True, _
Connection:= _
"Provider=Microsoft.ACE.OLEDB.12.0;User ID=Admin;Data Source=CurrentProject.FullName;" _
, SQLStatement:="SELECT * FROM `Acceptance_Letter`"
.Destination = 0 'wdSendToNewDocument
.Execute Pause:=False
End With
'------------------------------------------------
' Hide Word During Merge
'------------------------------------------------
oWord.Visible = False
totalRecord = DCount("*", "Acceptance_Letter")
Debug.Print ("totalRecord: " & totalRecord)
''Error
For recordNumber = 1 To totalRecord
Debug.Print ("Print: " & recordNumber)
outFileName = "Acceptance Letter - " & recordNumber
'------------------------------------------------
' Save file as Word Document
'------------------------------------------------
oWord.ActiveDocument.SaveAs2 wdOutputName & recordNumber & ".docx"
'------------------------------------------------
' Quit Word to Save Memory
'------------------------------------------------
oWord.Quit savechanges:=False
'------------------------------------------------
' Clean up memory
'------------------------------------------------
Set oWord = Nothing
Set oWdoc = Nothing
Next recordNumber
End Sub
Don't use apostrophes to delimit table name in SQL statement, use [ ]. Code fails if not used in statement assigned to SQLStatement property.
Quitting Word and cleaning memory inside loop is probably cause of error. However, I doubt that loop can save each record to individual doc file. This may require code looping through a recordset with field(s) that would be used as criteria to build filtered SQL for single record to merge, save Word doc, close Word docs, move to next record, repeat merge. Consider:
Sub startMergeAL()
Dim oWord As Object, oWdoc As Object, rs As DAO.Recordset
Set oWord = CreateObject("Word.Application")
Set rs = CurrentDb.OpenRecordset("SELECT ID FROM Acceptance_Letter")
' Hide Word During Merge
oWord.Visible = False
Do While Not rs.EOF
Set oWdoc = oWord.Documents.Open(CurrentProject.Path & "\Acceptance form V3.docx")
' Start mail merge
With oWdoc.MailMerge
.MainDocumentType = 0 'wdFormLetters
.OpenDataSource _
Name:=CurrentProject.FullName, _
LinkToSource:=True, _
AddToRecentFiles:=False, _
SQLStatement:="SELECT * FROM [Acceptance_Letter] WHERE ID = " & rs!ID, _
Connection:= _
"Provider=Microsoft.ACE.OLEDB.12.0;User ID=Admin;" & _
"Data Source=CurrentProject.FullName;"
.Destination = 0 'wdSendToNewDocument
.Execute Pause:=False
End With
' Save file as new Word Document
oWord.ActiveDocument.SaveAs2 CurrentProject.Path & "\Results\Acceptance Letter - " & _
Format(Now(), "yyyymmddmms") & "_" & rs!ID & ".docx"
oWord.ActiveDocument.Close False
oWdoc.Close False
rs.MoveNext
Loop
' Quit Word
oWord.Quit savechanges:=False
End Sub

Why are my MergeField names the only data pulling through to a PDF via MailMerge in Excel?

I am currently trying to use the code below in VBA to bring data in a table into a mailmerge word document which then saves the individual merges as a pdf. The code almost does this but when I run the macro on my excel sheet the pdf's saved only bring through the mergefield names from the word document and not the data itself.
Any ideas on where I can go from here? I am currently using Office 2016.
Sub RunMailMerge()
Dim objWord
Dim objDoc
Dim StrFolder As String, StrName As String, i As Long, j As Long
Dim strWorkbookName As String: strWorkbookName = ThisWorkbook.FullName
Const StrNoChr As String = """*./\:?|": StrName = "Easy.docx"
StrFolder = ThisWorkbook.Path & Application.PathSeparator
If Dir(StrFolder & strDocNm) = "" Then Exit Sub
Set objWord = CreateObject("Word.Application")
Set objDoc = objWord.Documents.Add
With objWord
'Disable alerts to prevent an SQL prompt
.DisplayAlerts = wdAlertsNone
'Display Word - change this to False once the code is running correctly
.Visible = False
'Open the mailmerge main document - set Visible:=True for testing
Set objWord = .Documents.Open(Filename:=StrFolder & StrName, ReadOnly:=True,
AddToRecentFiles:=False, Visible:=False)
With objWord
With .MailMerge
'Define the mailmerge type
.MainDocumentType = wdFormLetters
'Define the output
.Destination = wdSendToNewDocument
.SuppressBlankLines = False
'Connect to the data source
.OpenDataSource Name:=strWorkbookName, _
ReadOnly:=True, _
LinkToSource:=False, _
AddToRecentFiles:=False, _
Format:=wdOpenFormatAuto, _
Connection:="User ID=Admin;DataSource=strWorkbookName;" & _
"Mode=Read;Extended Properties=""HDR=YES;IMEX=1"";", _
SQLStatement:="SELECT * FROM `Sheet1 SQLStatement:=", _
SubType:=wdMergeSubTypeAccess
'Process all eligible records
For i = 1 To .DataSource.RecordCount
With .DataSource
.FirstRecord = i
.LastRecord = i
.ActiveRecord = i
'Exit if the field to be used for the filename is empty
If Trim(.DataFields("Tenant")) = "" Then Exit For
'StrFolder = .DataFields("Folder") & Application.PathSeparator
StrName = .DataFields("Tenant")
End With
.Execute Pause:=True
'Clean up the filename
For j = 1 To Len(StrNoChr)
StrName = Replace(StrName, Mid(StrNoChr, j, 1), "_")
Next
StrName = "Letter - " & Trim(StrName)
'Save as a PDF
objWord.SaveAs Filename:=StrFolder & StrName & ".pdf", _
FileFormat:=wdFormatPDF, AddToRecentFiles:=False
Next i
'Disconnect from the data source
.MainDocumentType = wdNotAMergeDocument
End With
'Close the mailmerge main document
.Close False
End With
Call CloseAll
Set wdDoc = Nothing: Set wdApp = Nothing
End With
End Sub
Sub CloseAll()
Dim objWord
Dim objDoc
Set objWord = CreateObject("Word.Application")
Set objDoc = objWord.Documents.Add
objWord.ActiveDocument.Close SaveChanges:=wdDoNotSaveChanges
End Sub
That code is essentially a copy of code I've posted elsewhere (e.g. https://www.mrexcel.com/forum/general-excel-discussion-other-questions/713478-word-2007-2010-mail-merge-save-individual-pdf-files-post4796480.html#post4796480), but why you'd add your call to CloseAll is a mystery.
Nonetheless, it's also clear you've also partially modified the code for use with late binding, by replacing:
Dim wdApp As New Word.Application, wdDoc As Word.Document
with:
Dim objWord
Dim objDoc
...
Set objWord = CreateObject("Word.Application")
Set objDoc = objWord.Documents.Add
Had you stuck with early binding throughout, the code would work. Right now, though, your modified code employs a mix of late binding with named Word constants, which are really only applicable to early binding. You need to fully adapt the code to late binding or revert to code that is entirely early binding.
Why are you trying to drive a mail merge via VBA code? You should be able to A) set up the data in Excel or Access, B) set up the template in Word & connect it to the data source, C) run the mail merge. Unless you're doing something really, really fancy, there should be no need for VBA.
Since it seems some sadist has forced you to do things the hard way, it looks like your error is most likely here:
Connection:="User ID=Admin;DataSource=strWorkbookName;" & _
"Mode=Read;Extended Properties=""HDR=YES;IMEX=1"";", _
SQLStatement:="SELECT * FROM `Sheet1
SQLStatement:=", _
SubType:=wdMergeSubTypeAccess
First of all:
Connection:="User ID=Admin;DataSource=strWorkbookName;" & _
should be
Connection:="User ID=Admin;DataSource=" & strWorkbookName & ";" & _
Second, your SQLStatement parameter is unterminated, and I'm pretty sure that "Sheet1" (not sure why you have an extra backtick in there) isn't the way to reference the "table" (i.e. worksheet) when selecting from an Excel workbook. IIRC, it should be "WorkBook$WorkSheet", so this:
SQLStatement:="SELECT * FROM `Sheet1
should be something like:
SQLStatement:="SELECT * FROM " & strWorkbookName & "$Sheet1", _
That line is followed by the end of the string
SQLStatement:=", _
which was part of the actual SQL string being sent to the database engine in Excel. That ain't gonna work.
The way I read it, that line should be:
Connection:="User ID=Admin;DataSource=" & strWorkbookName & ";" & _
"Mode=Read;Extended Properties=""HDR=YES;IMEX=1"";", _
SQLStatement:="SELECT * FROM " & strWorkbookName & "$Sheet1", _
SubType:=wdMergeSubTypeAccess
You may have to tweak it a bit, but I think that'll get you on the right track.

Excel Workbook to Create Word Document and Auto-Run Mail Merge from Excel Workbook

I've got a bit of a tricky one here. Attempting to simplify an existing process.
Existing Process:
Word Document ("Plan Doc Template") is entirely composed of INCLUDETEXT fields that pull Bookmarked sections from another Word Document ("Source Plan Doc" we'll call it) that includes merge-fields in its bookmarked sections which are from an Excel Workbook ("Mail Merge Workbook").
The current process involves the user copying a Plan Doc Template and a Mail Merge Workbook and pasting it into any folder they choose. The user then fills out the Mail Merge Workbook, saves and closes, and runs a Mail Merge through the Plan Doc Template Word Doc. This pulls in bookmarked sections from the Source Plan Doc depending on the Mail Merge Workbook fields selected. The user then removes all INCLUDETEXT fields with CTRL + SHIFT + F9 to turn fields of Plan Doc Template into workable text.
(Hopeful) Future Process:
The user copies a Mail Merge Workbook and pastes it into their
desired folder. Fills out the Mail Merge Workbook. (Manual Step)
Runs VBA Code.
VBA copies the Plan Doc Template and pastes in the Mail Merge Workbook's folder that just ran the VBA code.
VBA renames the Plan Doc Template Word Doc based on fields within the Mail Merge Workbook.
VBA runs a Mail Merge within the Plan Doc Template
VBA highlights entire document and CTRL + SHIFT + F9 to turn Field Codes into workable text.
Is it possible to do all this from an Excel VBA code or would I need a separate code after the Plan Doc has been created to run the mail merge and do the CTRL + SHIFT + F9 steps?
P.S. I use Excel Worksheets via DDE Selection to get the correct formatting from Mail Merge Workbook to Document. Hoping that can be included in the VBA code, as well.
Help would be greatly appreciated on this one, thanks,
Rich
It looks like you can have the whole thing run with one macro from Excel, without the user having to run a second one, using a For loop until wdApp.Documents.Count increases by 1. I did test the following, but with only a very small data set, so it ran very quickly.
Since the user might have more than just the main merge document open, it's important the code can identify and work with the resulting document. Usually, it will have become the ActiveDocument but relying on that is never certain. So I built in a couple of loops to 1) hold the currently open documents in an array then 2) compare those to the currently active document. If the currently active document is not in the array, then the fields are unlinked (that's the equivalent of Ctrl+Shift+F9).
Of course, if you really wanted to identify the new document from all the documents you'd need to loop each document and loop the array, making the comparison. But I've given you the starting point...
Sub MergeWithWord()
Dim wdApp As Object
Dim wdDoc As Object
Dim nrDocs As Long
Dim i As Long, d As Long
Dim aDocs() As Variant
Set wdApp = GetObject(, "Word.Application")
nrDocs = wdApp.documents.Count
'Get all opened documents so can compare whether a new one
ReDim Preserve aDocs(nrDocs - 1)
Set wdDoc = wdApp.activedocument
For i = 0 To nrDocs - 1
Set aDocs(i) = wdApp.documents(i + 1)
Next
If wdDoc.MailMerge.MainDocumentType <> -1 Then
wdDoc.MailMerge.Destination = 0
wdDoc.MailMerge.Execute False
Do Until wdApp.documents.Count > nrDocs Or i > 1000
i = i + 1
Loop
Set wdDoc = wdApp.activedocument
For d = 0 To UBound(aDocs)
If wdDoc Is aDocs(d) Then
Debug.Print "Not a new doc"
Else
Debug.Print wdDoc.FullName
wdDoc.Fields.Unlink
Exit For
End If
Next
End If
Debug.Print nrDocs, i
MsgBox "Done"
End Sub
May not be the most elegant code but here was what I wound up using to solve my question in case it helps anyone else.
Sub ButtonMerge()
Dim str1 As String
Dim PlanDocTemplate As String
Dim EDrive As String
Dim answer1 As Integer
Dim answer2 As Integer
answer1 = MsgBox("Is this IC Plan Workbook saved in the appropriate Client folder?", vbYesNo + vbQuestion)
If answer1 = vbNo Then
MsgBox ("Please save this IC Plan Workbook in the appropriate Client folder then run again.")
Exit Sub
Else
'do nothing
End If
str1 = "Q:\IC\New Structure\IC Toolkit\Templates\01 Plan Doc Template\16 Source\IC Plan Doc Template v1.0.docx"
PlanDocTemplate = Application.ActiveWorkbook.Path & "\" & Range("A1").Value & ".docx"
EDrive = "E:\" & Range("A1").Value & ".docx"
If Len(Dir(Application.ActiveWorkbook.Path & "\" & Range("A1").Value & ".docx")) = 0 Then
Call FileCopy(str1, PlanDocTemplate)
Else
MsgBox ("The Plan document already exists, please delete or rename the existing Plan Doc in folder " _
& Application.ActiveWorkbook.Path & "\ before creating a new one.")
Exit Sub
End If
strWorkbookName = ThisWorkbook.Path & "\" & ThisWorkbook.Name
Worksheets("Data").Activate
'Opens New Plan Doc Template
Set appWD = CreateObject("Word.Application")
appWD.Visible = True
appWD.Documents.Open Filename:=PlanDocTemplate
ActiveDocument.MailMerge.OpenDataSource Name:=strWorkbookName, _
Format:=wdMergeInfoFromExcelDDE, _
ConfirmConversions:=True, _
ReadOnly:=False, _
LinkToSource:=True, _
AddToRecentFiles:=False, _
PasswordDocument:="", _
PasswordTemplate:="", _
Revert:=False, _
Connection:="Entire Spreadsheet", _
SQLStatement:="SELECT * FROM `Data$`", _
SQLStatement1:="", _
SubType:=wdMergeSubTypeOther
appWD.Visible = True
appWD.Selection.WholeStory
appWD.Selection.Fields.Update
appWD.Selection.Fields.Unlink
ActiveDocument.MailMerge.MainDocumentType = wdNotAMergeDocument
appWD.ActiveDocument.Save
Worksheets("Form").Activate
MsgBox "Successfully Created " & Range("A1").Value & " in Location: " & Application.ActiveWorkbook.Path & "\"
answer2 = MsgBox("Do you want to save a draft in the E:\ drive as well?", vbYesNo + vbQuestion, "E: Drive Copy")
If answer2 = vbYes Then
If Dir("E:\") <> "" Then
ActiveDocument.SaveAs2 Filename:= _
"E:\" & Range("A1").Value & ".docx", _
FileFormat:=wdFormatXMLDocument, LockComments:=False, Password:="", _
AddToRecentFiles:=True, WritePassword:="", ReadOnlyRecommended:=False, _
EmbedTrueTypeFonts:=False, SaveNativePictureFormat:=False, SaveFormsData _
:=False, SaveAsAOCELetter:=False, CompatibilityMode:=14
MsgBox ("Successfully Created " & Range("A1").Value & " in E:\ Location.")
Exit Sub
Else
MsgBox ("Please open the E:\ drive and enter your username/password." & _
vbCrLf & vbCrLf & "Click Ok when E:\ drive is opened.")
If Len(Dir("E:\")) = 0 Then
MsgBox ("Error connecting to E:\ drive." & vbCrLf & vbCrLf & "Please ensure you're connected and try again.")
Exit Sub
Else
ActiveDocument.SaveAs2 Filename:= _
"E:\" & Range("A1").Value & ".docx", _
FileFormat:=wdFormatXMLDocument, LockComments:=False, Password:="", _
AddToRecentFiles:=True, WritePassword:="", ReadOnlyRecommended:=False, _
EmbedTrueTypeFonts:=False, SaveNativePictureFormat:=False, SaveFormsData _
:=False, SaveAsAOCELetter:=False, CompatibilityMode:=14
MsgBox ("Successfully Created " & Range("A1").Value & " in E:\ Location.")
Exit Sub
End If
End If
Else
Exit Sub
End If
End Sub

Use Field Code as File Name in Mail Merge

I want to separate my mail merge into separate PDF files (this part is working). But the file names are being saved as a counter i.e. numbers.
Sub AllSectionsToSubDoc()
Dim x As Long
Dim Sections As Long
Dim Doc As Document
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Set Doc = ActiveDocument
Sections = Doc.Sections.Count
For x = Sections - 1 To 1 Step -1
Doc.Sections(x).Range.Copy
Documents.Add
ActiveDocument.Range.Paste
ActiveDocument.SaveAs (Doc.Path & "\" & x & ".pdf")
ActiveDocument.Close False
Next x
Application.ScreenUpdating = True
Application.DisplayAlerts = True
End Sub
I want to extend this code so that it saves the files with file names which are NOT numbers, but are taken from one of the field codes that I specify.
For example if I specify field code «First_Name» as the file name in my VBA code, and there are 3 names - (John, Peter, Samuel) 3 files should be saved in my destination folder as John.pdf, Peter.pdf, Samuel.pdf
Get the value from the data source, Split between commas, loop through the returned array and save each document individually.
Something like this (I haven't been able to test it).
Dim Value As String
Dim Names As Variant
Dim idx As Long
Value = Doc.DataSource.DataFields("First_Name").Value
Names = Split(Value, ",")
For idx = LBound(Names) To UBound(Names)
ActiveDocument.SaveAs Doc.Path & "\" & Names(idx) & ".pdf"
Next
In the event where the value is a single name (no comma), the Split() function will return an array with a single element.
I managed to find a very simple solution to this. After creating the mail merge, I previewed the results and ran the following macro
ChangeFileOpenDirectory "C:\User\Documents\folder\"
ActiveDocument.ExportAsFixedFormat OutputFileName:= _
" C:\User\Documents\folder\" & ActiveDocument.MailMerge.DataSource.DataFields("Field") & ".pdf", _
ExportFormat:=wdExportFormatPDF, OpenAfterExport:=False, OptimizeFor:= _
wdExportOptimizeForOnScreen, Range:=wdExportAllDocument, From:=1, To:=1, _
Item:=wdExportDocumentContent, IncludeDocProps:=True, KeepIRM:=True, _
CreateBookmarks:=wdExportCreateNoBookmarks, DocStructureTags:=True, _
BitmapMissingFonts:=True, UseISO19005_1:=False
ActiveDocument.MailMerge.DataSource.ActiveRecord = wdNextRecord
and then just loop until the end