Thursday, January 3, 2008

Castle Facility for Windows Fax Services

Some months ago, at work I was facing the need to send faxes from the main application server. "No problem", you might say, "just use Windows Fax Services". But the fax server was far, far away, only to be accessed through the internet. So I wrote a wrapper Castle facility around the fax API and published it as a SOAP-WS. Interfaces and implementation are in separate assemblies, so the ws-client doesn't have to depend on fxscomex.dll et al (the Windows Fax DLLs). It is also possible to send faxes via email, by setting up a couple of components outside the facility. These components periodically check an IMAP account for the destination fax number from the subject and the actual fax as an attachment. Usually you would send a TIF or PDF for faxing. Plain text also works, but I guess nobody would use that...

Ok, here's a more formal documentation:

Usage

The facility (Castle.Facilities.WindowsFax.dll) should be installed and configured on the machine that is the direct client of the fax server.

Required assemblies:

  • Castle.Facilities.WindowsFax.dll
  • Castle.Components.Fax.WindowsFaxService.dll
  • Castle.Components.Fax.dll
  • Castle.Core.dll
  • Castle.MicroKernel.dll
  • Interop.FAXCOMEXLib.dll
  • Windows Fax installed

Those are the bare minimum assemblies required, however you probably already have also Castle.Windsor, so I'm going to assume that for the rest of this documentation. If you don't have Windsor for some reason, you'll have to configure it manually using MicroKernel or provide your own configuration.

Configuration

<facility id="fax" type="Castle.Facilities.WindowsFax.WindowsFaxFacility, Castle.Facilities.WindowsFax">
  <serverName>localhost</serverName>
</facility>

<serverName> refers to the machine that has the actual Windows Fax Service running, the one with the actual fax hardware. If not specified, localhost is assumed.

To make a fax operation, ask the Windsor container for Castle.Components.Fax.IFaxService, it has all the operations.

Scenario 1: Local fax server

If your fax server is on the web server's network, just drop the configuration above in your windsor config, setup the fax server name and you're good to go.

Scenario 2: Fax server is on another network

Here you can use the SOAP web services provided (client proxy here) or alternatively use remoting, WCF, etc. Leaving firewalls aside, it looks like this:

 

Dibujo3

 

Required assemblies on "Web App Server":

  • Castle.Components.Fax.dll
  • Castle.Components.Fax.WebServiceClient.dll

On "Fax Web Server", just install the web service provided.

Sending faxes by email

The web service miniapp also comes with the optional components to send faxes via mail. It works by periodically polling an IMAP account for mails with subject with the format "<fax number>, <fax subject>"

  • IMAPClientWrapper is just a wrapper around Lumisoft's excellent IMAP Client.
  • MailFaxSender is the one that does the actual work of checking the mail account and sending any pending faxes found.
    This component takes the following configuration:
    • Username, Password: to access the IMAP account
    • Server, ServerPort: to the IMAP server
    • FolderInbox: IMAP folder where to look for new faxes
    • FolderError: IMAP folder where faxes processed with errors are stored.
    • FolderSent: IMAP folder where sent faxes are stored.
    • FolderNotFax: IMAP folder where mails not related to the fax service (ie doesn't comply with the subject format specified above) are stored.
    These IMAP folders are automatically created when needed.
  • MailSenderScheduler is a basic scheduler that executes the IMAP polling every x minutes. It relies on the startable facility to be...er... started.
    Configuration: SleepingMinutes: pretty much self explanatory.

Troubleshooting

  • Problem: I can't perform any fax operation, I always get some COM Operation Failed exception.
    Solution: Make sure the fax service is running. If it's not that, it's probably a matter of permissions. Open the Fax Console, Tools -> Fax Service Manager, right-click on Fax (Local), Properties, Security tab, allow all operations to the user running the facility (probably NETWORK SERVICE or ASPNET). Also check the permissions on the fax printer: from the Fax Console, Tools -> Fax Printer Configuration, Security tab, etc.
  • Problem: I can't send PDF files.
    Solution: Install Acrobat 4, then modify the path on the registry file acrobat_printto.reg, then apply that reg. UPDATE: also try HKCR\AcroExch.Document.x\shell\Printto\command (where x is the acrobat version)
    Explanation: Windows fax services sends different file types by printing them internally to the fax printer. This registry modification tells Windows to use Acrobat 4 to print the PDF. Why Acrobat 4 and not the latest version? Because Adobe has removed the support in Reader to directly print a PDF. UPDATE: turns out this still works with Acrobat 8.1. Couldn't get it working with Acrobat 9 though.
  • Problem: I can't send DOC (Word) files.
    Solution: DOC files are not supported (if you find something to print docs on the server reliably (ie NOT Microsoft Word) please tell me)

TODO

  • Generalize it to support Hylafax and other fax providers.
  • Support POP3

Project homepage at SourceForge.

SVN repository.

No comments: