I’ve spent some time working with Asterisk and faxes this weekend. By itself, Asterisk doesn’t know much about faxing. It’s able to spot incoming faxes and yank them out of IVR menus, but that’s about it.

Fortunately, Asterisk is extensible, and someone has written a software faxmodem plugin for it. More specifically, Steve Underwood has written SpanDSP, a more or less complete fax modem, plus a couple Asterisk applications (RxFax and TxFax) for sending and receiving faxes. The applications still need a bit of polishing (as far as I can tell, there’s no way to extract fax metadata from them, like the speed of the connection, the caller’s fax number, and so forth), but they work, and he’s spitting out a couple new releases per week, adding workarounds for increasing numbers of broken fax devices.

I probably wouldn’t trust SpanDSP with all of my company’s faxes today, but it’s improving so quickly that I’ll probably want to revisit that conclusion in a month or two. In preparation for that day, I’m prototyping what it takes to add direct-dialed fax extensions to Asterisk, and then deliver the faxes via email. It turned out to be surprisingly easy.

First, add this to the top of your /etc/asterisk/extensions.conf file:

[macro-faxreceive]
  exten => s,1,SetVar(FAXFILE=/var/spool/asterisk-fax/${UNIQUEID}.tif)
  exten => s,2,DBGet(EMAILADDR=extensionemail/${MACRO_EXTEN})
  exten => s,3,rxfax(${FAXFILE})
  exten => s,103,SetVar(EMAILADDR=defaultuser@example.com)
  exten => s,104,Goto(3)

Next, create a ‘fax’ context in Asterisk and add all of your fax extensions to it. This seems to be the easiest way to have a script run whenever a fax line hangs up, but not run it on every call (hmm, how does this work if you include the fax context into ‘outside’?):

[fax]
  exten => 2201,1,Macro(faxreceive)
  exten => 2202,1,Macro(faxreceive)
  exten => 2203,1,Macro(faxreceive)

  exten => h,1,system(/usr/local/sbin/mailfax ${FAXFILE} \
        ${EMAILADDR} "${CALLERIDNUM} ${CALLERIDNAME}")

Of course, incoming fax calls have to make it to this extension. Here’s part of my ‘outside’ context that hands fax calls off to the fax context:

[outside]
  exten => 2125551212,1,Goto(fax,5555,1)
  exten => fax,1,Goto(fax,2201,1)

The ‘fax’ line will catch any faxes that end up autodetected in the middle of an IVR or voicemail prompt.

SpanDSP receives faxes into TIFF files, but they’re kind of a pain to view, so I’m converting them to PDFs inside of /usr/local/sbin/mailfax:

#!/bin/sh

FAXFILE=$1 
RECIPIENT=$2
FAXSENDER=$3

tiff2ps -2eaz -w 8.5 -h 11 $FAXFILE | 
  ps2pdf - |
  mime-construct --to $RECIPIENT --subject "Fax from $FAXSENDER" \
    --attachment fax.pdf --type application/pdf --file - 

There’s just one final step. Rather then code extension-to-email mapping directly into extensions.conf, I added a lookup via Asterisk’s internal database. So, you need to add DB entries for each extension. This is pretty easy; from the Asterisk CLI just type:

*CLI> database put extensionemail 2202 bob@example.com

You can verify that it worked by running ‘database show’.

One comment on fax and VoIP: conventional wisdom holds that the two don’t mix. At the very least, you can’t send faxes over a compressed VoIP link, although uncompressed (the G.711 ULAW codec in Asterisk) will probably work over a LAN. I haven’t tested it. In general, stick to faxing over traditional telephone interfaces, like POTS lines, ISDN, or T1s, and you’ll be happier.

Two final things: First, I’m fairly new to Asterisk. There’s probably an easier way then the way I’ve done it here. See the comment about ‘include =>’ above. Second, I’m kind of trusting Asterisk not to put nasty shell metacharacters into the parameters that I’m passing to mailfax. That’s probably not a good assumption; consider auditing the Asterisk code a bit, or just remove the caller ID name from the call to mailfax.