Word: Merge to fax (in Windows 2000 and later)

Home Up

 

 

Google
 


 

Merge to fax the "official" way

If you have Windows 2000 or Windows XP, the "official" way to merge to fax is to have the full Outlook (not Outlook Express) installed on your system, then merge to e-mail - see e.g.

http://support.microsoft.com/default.aspx?scid=kb;EN-US;289532

Problems

There are problems. Briefly, 
 a. the "Merge to fax" button/option is never enabled in Word 2003, and probably never enabled in Word 2002/2000 on Win2k and later.
 b. although it is possible to enable the "Merge to fax" button, Word actually uses exactly the same method to send a fax (i.e. via MAPI/Outlook) as it uses to send an e-mail. The only difference is that you see a slightly different Word dialog box for setting up the fax.
 c. if you want to fax to one of the new Internet fax services such as Venali, I think your only option is to use  "Merge to e-mail"
 d. but, as far as I know, if you have any images in your fax, faxing via "merge to e-mail" will not format your document correctly. It's the step that renders the e-mail into fax format that goes wrong.

Enabling the Merge to Fax button

If you really want to enable the "Merge to fax" button, you need to create a file called msmail.ini in your Windows directory (or WINNT directory or whatever) with at least the following lines:

[EFAX Transport]
LocalFax=1

A macro for simple merges to fax

You may be able to get a third-party solution such as Winfax. I can't help you there.

If you want to merge to a faxmodem and your merge is fairly simple (one fax for each record in the data source) you could try the following macro. However, in Windows 2000 you may need to install the Windows fax software first. To do that. try Control Panel|Add/Remove programs|Add/Remove Windows Components first.

If you're going to try the macro, please read the notes, modify the macro to suit your needs, and test it. The macro seems to have worked for other users.

If you're unfamiliar with VBA, getting this to work could be quite difficult. A useful starting point is the Word MVPs site at http://word.mvps.org/  and specifically the following "get-you-started" article

http://word.mvps.org/word/FAQs/­MacrosVBA/CreateAMacro.htm

You can also download a Word 2003 document containing the macros by right-clicking this link.

Finally, I was unable to make this macro work on client computers connected to the Shared Fax Service that is provided as part of Microsoft's Small Business Server 2003 (SBS). As far as I can tell the problem is that the old fax objects are unable to connect to the fax server, so I have written a further macro that uses the new fax objects which appear to overcome this problem. However, because the new fax objects are only provided with Windows XP (and later) I do not have a method which will definitely allow a Windows 2000 user to send faxes via the SBS fax server, and I have no way of testing what happens with earlier versions of SBS.

Here is the code for the original macro:

Sub MergeOneFaxPerSourceRec()


' Disclaimer: Use this macro at your own risk.
'
' Purpose: Perform one Word mailmerge for each record in
' a Word data source, sending the results of each merge
' to a different fax number specified in a column of the
' the data source
'
' Author: Peter J Jamieson
'
' Date: November 2003
'
' Assumes:-
' Word 2000 or later (Word 97 might work)
' Windows 2000 or later, with the standard fax service
' software installed and configured to use a working fax
' device
' You have used Tools|References in the VBA editor to
' add the appropriate type library, which is:
' "Faxcom 1.0 Type Library"
' You correctly adapt the macro to your environment
' Overview:-
' The routine performs one merge per record in the data
' source. For each merge, the macro:
' - creates a new Word document
' - "prints" the document to the Fax printer, but
'   outputting the result to a .tif file rather than
'   allowing the fax printer to send the fax directly.
'   This allows us to specify the fax number etc. in the
'   macro rather than having to respond to the fax
'   printer's dialog box.
' - submits the tif file to the fax service
' - discards the Word document
'
' Notes:-
' This does not use the Extended Fax client API
' because it is not available in Windows 2000.
'
' This macro relies on the fax service to deliver the
' faxes once they have been submitted. You should use
' the fax service to verify which faxes have been sent
' and which, if any, failed. The fax service should
' retain a copy of each fax submitted so that
' retransmission should be feasible from within the
' service, i.e. without re-running the merge.
'
' NB, this macro needs bettor error management and
' doubtless other things a VBA expert would point out.
'
'
' Specify the path for the .tif files saved by the Fax Printer
' This path must exist and the name should end with "\"
Const sTifFolder = "c:\tif\"
' Specify the name of the .tif file to output
Const sTifFile = "mergetif.tif"
' Specify the fax printer name that makes it all work
Const sFaxPrinter = "Fax"

Dim bFaxPortAvailable As Boolean
Dim bFaxServerAvailable As Boolean

Dim bTerminateMerge As Boolean

Dim lJobID As Long
Dim lSourceRecord As Long

Dim oApp As Word.Application
Dim oDataFields As Word.MailMergeDataFields
Dim oDoc As Word.Document
Dim oFaxDoc As FAXCOMLib.FaxDoc
Dim oFaxPort As FAXCOMLib.FaxPort
Dim oFaxPorts As FAXCOMLib.FaxPorts
Dim oFaxServer As FAXCOMLib.FaxServer
Dim oMerge As Word.MailMerge

Dim sActivePrinter As String
Dim sTifPath As String

' Phase 1.
' Connect to the Fax server
' and optionally see if a Port is available

Set oFaxServer = CreateObject("FaxServer.FaxSer­ver")

If oFaxServer Is Nothing Then
  MsgBox "Could not create a fax server object"
  bFaxServerAvailable = False
Else
  ' This should connect us to the fax server on the current machine
  oFaxServer.Connect Servername:=Environ("computern­ame")
  bFaxServerAvailable = True
  bFaxPortAvailable = True

  ' begin optional section
  ' - ensure that at least one output port is available
  ' - not essential but we will just see an error later
  ' if no output port is available
  Set oFaxPorts = oFaxServer.GetPorts
  If oFaxPorts.Count = 0 Then
    MsgBox "The fax server has no fax devices"
    bFaxPortAvailable = False
  Else
    ' look for a port that can send
    For i = 1 To oFaxPorts.Count
      Set oFaxPort = oFaxPorts.Item(i)
      If oFaxPort.Send = 0 Then
        Set oFaxPort = Nothing
      Else
        Exit For
      End If
    Next
    If oFaxPort Is Nothing Then
      MsgBox "The fax server has no ports configured to send faxes"
      bFaxPortAvailable = False
    Else
      ' at the moment we do not use the FaxPort object to get status
      ' info. so just get rid of it
      Set oFaxPort = Nothing
    End If
  End If
  ' we do not need this either
  Set oFaxPorts = Nothing
  ' end optional section

End If

' Phase 2.
' We can fax, so set up the printer
' and start the merges.

If bFaxServerAvailable And bFaxPortAvailable Then

  ' You may need to change this
  Set oApp = Application

  ' The mail merge main document is assumed
  ' to be the active document in the current
  ' instance of Word
  Set oDoc = oApp.ActiveDocument
  Set oMerge = oDoc.MailMerge
  Set oDataFields = oMerge.DataSource.DataFields

  ' save and set up the active printer
  sActivePrinter = oApp.ActivePrinter
  ' don't change the printer if it is already
  ' correctly set up
  ' (I had problems when I tried to switch
  ' to the fax printer in code)
  ' you may need to adjust this for your
  ' fax printer name
  If Left(sActivePrinter, 3) <> sFaxPrinter Then
    oApp.ActivePrinter = sFaxPrinter
  End If

  With oMerge

  ' If no data source has been defined,
  ' do it here using OpenDataSource.
  ' But if it is already defined in the document,
  ' you should not need to define it here.

  ' .OpenDataSource _
  ' Name:="whatever"

  lSourceRecord = 1
  bTerminateMerge = False

  Do Until bTerminateMerge
    .DataSource.ActiveRecord = lSourceRecord

    ' if we have gone past the end
    ' (and possibly, if there are no records)
    ' then the Activerecord will not be what
    ' we have just tried to set it to

    If .DataSource.ActiveRecord <> lSourceRecord Then
      bTerminateMerge = True
    Else
      .DataSource.FirstRecord = lSourceRecord
      .DataSource.LastRecord = lSourceRecord
      .Destination = wdSendToNewDocument
      .Execute

      ' Word always sets the output document produced
      ' by the merge to be the ActiveDocument

      ' Now print to the fax printer, specifying an
      ' OutputFileName.
      ' Specifying Background:=False is
      ' particularly important or the fax stage
      ' will fail later

      ' create the full path name for the file.
      ' (done separately so you can change the way
      ' you create the name and re-use the name later)

      sTifPath = sTifFolder + sTifFile
      oApp.PrintOut _
        Background:=False, _
        Append:=False, _
        Range:=wdPrintAllDocument, _
        OutputFileName:=sTifPath, _
        Item:=wdPrintDocumentContent, _
        Copies:=1, _
        PageType:=wdPrintAllPages, _
        PrintToFile:=True

      ' Don't need the document any more
      oApp.ActiveDocument.Close Savechanges:=False

      ' Now make a FaxDocument
      Set oFaxDoc = oFaxServer.CreateDocument(sTif­Path)
      If oFaxDoc Is Nothing Then
        MsgBox "Could not create the fax document"
        ' you could consider finishing here by setting
        ' TerminateMerge = True
      Else
        ' fill in whatever details you need
        ' from the data source or elsewhere
        With oFaxDoc
          ' The number to send to. The only really essential
          ' piece of information. Here we get it from
          ' a field in the data source called "faxnumber"
          .FaxNumber = oDataFields("faxnumber")

          ' DisplayName is a "user-friendly" name used
          ' by the Fax Server when you e.g. inspect the
          ' current fax status

          ' here we get it from a field in the data source
          ' called ufname
          .DisplayName = oDataFields("ufname")
          ' here we just set it to ""
          '.DisplayName = ""

          ' If you want a cover page, set SendCoverPage
          ' to a nonzero value. You could define whether
          ' or not you want a cover page, and which
          ' page to use, in your data source. However,
          ' if you specify a cover page, you /must/
          ' provide a valid name for the page. This code
          ' does not verify whether you do or not.
          .SendCoverpage = 0

          ' If the cover page (.cov file) is a common
          ' cover page located on the server (i.e. in the
          ' default folder), set ServerCoverPage=-1
          ' and provide the name of the cover page
          ' If the cover page is somewhere else,
          ' set ServerCoverPage=0 and specify the
          ' full path name of the cover page
          .ServerCoverpage = 1
          .CoverpageName = ""

          ' The following items may be used in the coverpage
          ' or they may be displayed in fax service status
          ' dialog boxes. The items visible in the Win2000
          ' fax status are indicated by
          '** displayed in dialog

          .CoverpageNote = ""
          .CoverpageSubject = ""
          .EmailAddress = ""
          .RecipientAddress = ""
          .RecipientCity = ""
          .RecipientCompany = ""
          .RecipientCountry = ""
          .RecipientDepartment = ""
          .RecipientHomePhone = ""

          '** displayed in dialog
          .RecipientName = ""
          .RecipientOffice = ""
          .RecipientOfficePhone = ""
          .RecipientState = ""
          .RecipientTitle = ""
          .RecipientZip = ""
          .SenderAddress = ""

          '** displayed in dialog
          .SenderCompany = ""

          '** displayed in dialog
          .SenderDepartment = ""
          .SenderFax = ""
          .SenderHomePhone = ""

          '** displayed in dialog
          .SenderName = ""
          .SenderOffice = ""
          .SenderOfficePhone = ""
          .SenderTitle = ""

          '** displayed in dialog
          .BillingCode = ""

          ' DiscountSend = 0 means "send immediately
          ' If you have set up discount periods, setting
          ' DiscountSend to a nonzero value will make the
          ' fax service send in a discount period
          .DiscountSend = 0

          ' In theory, the TSID is the Fax sender ID printed
          ' on the fax, i.e. typically your contact fax number,
          ' but the value set up in the fax service appears to
          ' override any value set here.
          '.Tsid = ""
        End With

        ' Now send the thing. We don't actually do anything
        ' with the ID except check it is nonzero

        lJobID = oFaxDoc.Send()
        Set oFaxDoc = Nothing
      End If
    End If
    ' move to the next record
    lSourceRecord = lSourceRecord + 1
  Loop
End With

' All done. Restore the previous printer
' if necessary. You may need to tweak this
If Left(sActivePrinter, 3) <> sFaxPrinter Then
  oApp.ActivePrinter = sActivePrinter
End If

Set oDataFields = Nothing
Set oMerge = Nothing
Set oDoc = Nothing

'Set oApp = Nothing

End If

If bFaxServerAvailable Then
  oFaxServer.Disconnect
  Set oFaxServer = Nothing
End If

End Sub

Here is the code for the macro for use with Small Business Server clients:

Sub MergeOneFaxPerSourceRecEx()

' Disclaimer: Use this macro at your own risk.
'
' Purpose: Perform one Word mailmerge for each record in
' a Word data source, sending the results of each merge
' to a different fax number specified in a column of the
' the data source
'
' Author: Peter J Jamieson
'
' Date: July 2005
'
' Assumes:-
' Word 2000 or later (Word 97 might work)
' Windows XP or later, with the standard fax service
' software installed and configured to use a working fax
' device, or a connection to a shared fax server - this
' has only been tested by the one provided in
' Windows Small Business Server 2003. Note that the
' FaxDocument.Submit and FaxDocument.SubmitConnected
' methods will fail - and therefore this code will fail -
' if the server is a Windows XP machine.
' You have used Tools|References in the VBA editor to
' add the appropriate type library, which is:
' "Microsoft Fax Service Extended COM Type Library"
' You correctly adapt the macro to your environment
'
' Overview:-
' The routine performs one merge per record in the data
' source. For each merge, the macro:
' - creates a new Word document
' - "prints" the document to the Fax printer, but
' outputting the result to a .tif file rather than
' allowing the fax printer to send the fax directly.
' This allows us to specify the fax number etc. in the
' macro rather than having to respond to the fax
' printer's dialog box.
' - submits the tif file to the fax service
' - discards the Word document
'
' There are a number of significant differences from the
' version of the code that used the old fax server objects:
' - this version is really intended for use with a Windows
' SBS shared Fax server.
' - We do not try to get information about the available
' devices on the server. You may be able to do this if you
' want, e.g. using the FaxOutboundRouting object

' Notes:-

' This macro is based on MergeOneFaxPerSourceRec

' This routine uses the Extended Fax client API
' which is only available on Windows XP or later
'
' This macro relies on the fax service to deliver the
' faxes once they have been submitted. You should use
' the fax service to verify which faxes have been sent
' and which, if any, failed. The fax service should
' retain a copy of each fax submitted so that
' retransmission should be feasible from within the
' service, i.e. without re-running the merge.
'
' NB, this macro needs bettor error management and
' doubtless other things a VBA expert would point out.
'
'
' Specify the name of the fax server computer
Const sFaxServerName = "myserver"
' For a local connection, leave the name blank
'Const sFaxServerComputer = ""

' Specify the path for the .tif files saved by the Fax Printer
' This path must exist and the name should end with "\"
Const sTifFolder = "c:\tif\"
' Specify the name of the .tif file to output
Const sTifFile = "mergetif.tif"
' Specify the fax printer name that makes it all work
' This printer is used purely to render the document
' as a .tif file, not to send the fax
Const sFaxPrinter = "Fax"

Dim bFaxServerAvailable As Boolean

Dim bTerminateMerge As Boolean

' The JobID needs to be able to contain
' an array of Job IDs
Dim lJobID As Variant
Dim lSourceRecord As Long

Dim oApp As Word.Application
Dim oDataFields As Word.MailMergeDataFields
Dim oDoc As Word.Document
Dim oFaxDoc As FAXCOMEXLib.FaxDocument
Dim oFaxServer As FAXCOMEXLib.FaxServer
Dim oMerge As Word.MailMerge

Dim sActivePrinter As String
Dim sTifPath As String

' Phase 1.
'
' Connect to the Fax server
' (We could put everything into an outer if..then..else
' block but I'm leaving it like the old routine for now)

Set oFaxServer = CreateObject("FaxComEx.FaxServer")

If oFaxServer Is Nothing Then
  MsgBox "Could not create a fax server object"
  bFaxServerAvailable = False
Else
  ' This should connect us to the fax server on the current machine
  oFaxServer.Connect bstrServername:=sFaxServerName
  bFaxServerAvailable = True
End If

' Phase 2.
' We think we can fax, so set up the printer
' and start the merges.

If bFaxServerAvailable Then

  ' You may need to change this
  Set oApp = Application

  ' The mail merge main document is assumed
  ' to be the active document in the current
  ' instance of Word
  Set oDoc = oApp.ActiveDocument
  Set oMerge = oDoc.MailMerge
  Set oDataFields = oMerge.DataSource.DataFields

  ' save and set up the active printer
  sActivePrinter = oApp.ActivePrinter
  ' don't change the printer if it is already
  ' correctly set up
  ' (I had problems when I tried to switch
  ' to the fax printer in code)
  ' you may need to adjust this for your
  ' fax printer name
  If Left(sActivePrinter, 3) <> sFaxPrinter Then
    oApp.ActivePrinter = sFaxPrinter
  End If

  With oMerge

  ' If no data source has been defined,
  ' do it here using OpenDataSource.
  ' But if it is already defined in the document,
  ' you should not need to define it here.

  ' .OpenDataSource _
  ' Name:="whatever"

  lSourceRecord = 1
  bTerminateMerge = False

  Do Until bTerminateMerge
    .DataSource.ActiveRecord = lSourceRecord

    ' if we have gone past the end
    ' (and possibly, if there are no records)
    ' then the Activerecord will not be what
    ' we have just tried to set it to

    If .DataSource.ActiveRecord <> lSourceRecord Then
      bTerminateMerge = True
    Else
      .DataSource.FirstRecord = lSourceRecord
      .DataSource.LastRecord = lSourceRecord
      .Destination = wdSendToNewDocument
      .Execute

      ' Word always sets the output document produced
      ' by the merge to be the ActiveDocument

      ' Now print to the fax printer, specifying an
      ' OutputFileName.
      ' Specifying Background:=False is
      ' particularly important or the fax stage
      ' will fail later

      ' create the full path name for the file.
      ' (done separately so you can change the way
      ' you create the name and re-use the name later)

      sTifPath = sTifFolder + sTifFile
      oApp.PrintOut _
        Background:=False, _
        Append:=False, _
        Range:=wdPrintAllDocument, _
        OutputFileName:=sTifPath, _
        Item:=wdPrintDocumentContent, _
        Copies:=1, _
        PageType:=wdPrintAllPages, _
        PrintToFile:=True

      ' Don't need the document any more
      oApp.ActiveDocument.Close Savechanges:=False

      ' Now make a FaxDocument
      Set oFaxDoc = CreateObject("FaxComEx.FaxDocument")
      If oFaxDoc Is Nothing Then
        MsgBox "Could not create the fax document"
        ' you could consider finishing here by setting
        ' TerminateMerge = True
      Else
        ' fill in whatever details you need
        ' from the data source or elsewhere
        With oFaxDoc

          ' The file to send. It might be possible to
          ' skip the "print to .tif" step earlier and
          ' simply submit the .doc, but I leave you to
          ' experiment

          .Body = sTifPath

          ' The number to send to. The only other really
          ' essential piece of information. You can specify
          ' more than one. Here we get a single fax number
          ' from a field in the data source called
          ' "faxnumber" and set the recipient name to ""
          .Recipients.Add _
            bstrFaxnumber:=oDataFields("faxnumber"), _
            bstrRecipientName:=oDataFields("faxname")

          ' If you want a cover page, set
          ' CoverPageType = fcptLOCAL
          ' if the cover page is on the local
          ' (client) machine or set
          ' .CoverPageType = fcptSERVER
          ' if the cover page is on the fax server
          ' machine, then set .Coverpage to the name
          ' of the cover page file. You can then also
          ' set some note text in .Note
          ' Otherwise, set
          .CoverPageType = fcptNONE
          '.CoverPage = "generic.cov"
         
          ' Cover page note
          '.Note = ""

          ' DocumentName is a "user-friendly" name used
          ' by the Fax Server when you e.g. inspect the
          ' current fax status

          ' here we get it from a field in the data source
          ' called ufname
          .DocumentName = oDataFields("ufname")
          ' here we just set it to ""
          '.DocumentName = ""

          ' Subject is potentially more important as
          ' it is used in the fax status display,
          ' potentially on cover pages, and if you are
          ' using e-mail notifications it is also used
          ' in the Subject line of the e-mail

          ' Here, we use the same ufname field as for
          ' DocumentName

          .Subject = oDataFields("ufname")

          ' See the MSDN Library documentation for the
          ' following fields

          ' The default priority is LOW
          .Priority = fptLOW

          ' you can send a delivery notification as a message
          ' box on a specific computer. When I tried this, it
          ' did not work, but that may simply be because of
          ' firewall rules or other security settings

          '.ReceiptType = frtMSGBOX

          ' or you can send a message via SMTP email if
          ' your server is suitably equipped:

          '.ReceiptType = frtMAIL
          ' Put the e-mail address in here
          '.ReceiptAddress = ""

          ' otherwise, specify no receipt:
          .ReceiptType = frtNONE

          ' Other receipt-related fields

          ' Attach a copy of the fax to the receipt e-mail
          ' .AttachFaxToReceipt = True

          ' If you are sending to multiple recipients,
          ' the fax server will send multiple faxes
          ' set this to true if you only want one
          ' e-mail receipt, false if you want one per fax
          ' .GroupBroadcastReceipts = False


          With .Sender

            ' Most of the sender details only
            ' actually appear somewhere if
            ' you use a cover page that uses them

            ' you can retrieve the default
            ' sender information (as specified in
            ' the fax Configuration Wizard I think):
            '.LoadDefaultSender

            ' a billing code of your choice
            .BillingCode = ""

            ' not currently supported
            '.City = ""

            ' sender's company name. This appears in
            ' the fax header and it may also appear on
            ' a cover page
            .Company = ""

            ' not currently supported
            ' in StreetAddress

            ' .Country = ""

            ' Sender's department name
            .Department = ""

            ' Sender's e-mail name
            .Email = ""

            ' Sender's fax number

            .FaxNumber = ""

            ' Sender's home phone number
            .HomePhone = ""

            ' Sender's name
            .Name = ""

            ' Sender's office location
            ' (this is just a piece of text)
            .OfficeLocation = ""

            ' Sender's Office phone
            .OfficePhone = ""

            ' Sender's state - currently in StreetAddress
            '.State = ""

            ' Sender's snailmail address (in essence)
            .StreetAddress = ""
            ' For a multiline address do, e.g.
            '.StreetAddress = "streetaddress1" & vbCrLf & "streetaddress2"

            ' Sender's Title
            ' (job title? Personal title?
            ' it's up to you

            .Title = ""

            ' Probably the sender ID - not supported
            '.Tsid = ""

            ' Sender's ZIP/Post code.
            ' Currently in StreetAddress
            ' .ZipCode = ""
          End With

          ' See the MSDN Library documentation for the
          ' following fields

          ' The schedule type lets you specify that you
          ' want to send the fax now, at a specific time,
          ' or in the discount rate period you specified
          ' for the fax device. The default is "now"
          .ScheduleType = fstNOW

          ' if you specify a time it must be the correct
          ' type of data
          '.ScheduleTime = CDate("16:25:00")
         
        End With

        ' Now send the thing. We don't actually do anything
        ' with the ID

        lJobID = oFaxDoc.ConnectedSubmit(oFaxServer)

        Set oFaxDoc = Nothing
      End If
    End If
    ' move to the next record
    lSourceRecord = lSourceRecord + 1
  Loop
End With

' All done. Restore the previous printer
' if necessary. You may need to tweak this
If Left(sActivePrinter, 3) <> sFaxPrinter Then
  oApp.ActivePrinter = sActivePrinter
End If

Set oDataFields = Nothing
Set oMerge = Nothing
Set oDoc = Nothing

'Set oApp = Nothing

End If

If bFaxServerAvailable Then
  oFaxServer.Disconnect
  Set oFaxServer = Nothing
End If

End Sub


 

 

Google
 

Please post any follow-up questions to this article in the Microsoft public newsgroup on mailmerge and fields. If you are using a newsreader such as Outlook Express, the server is at news://news.microsoft.com and the Mailmerge newsgroup is at news://news.microsoft.com/microsoft.public.word.mailmerge.fields. Otherwise, you can go to the Microsoft Communities home at  http://www.microsoft.com/communities and look for the group. For some reason it is currently named "Mailmerge and Fax"
Disclaimer

Peter Jamieson's Tip Pages: Copyright © 2005-2007, Peter Jamieson

Terms of Use