Inbound Fax Server

[Ref: OpenBSD 5.1, Asterisk 1.8.11 (from ports) | AST Fax | ReceiveFAX | Doxygen Docs | Extension Names and Patterns | Extensions.conf - the Dial Plan ]

Table of Contents
  1. Introduction
  2. Dialplan
    • Default Config
    • Incoming Fax Number
    • Macro Fax Receipt
      • Diagnostics
  3. ${FAX2EMAIL} script


Make sure you have a functioning Asterisk box, and have installed the above dependencies before you continue.


[Ref: ReceiveFax

Asterisk can handle faxes through the Dialplan application RecieveFax

File extracts: /etc/asterisk/extensions.conf

Default Configuration

I set up some global variables in the [globals] section so that I don’t have to re-type them further down in the dialplan, which for me minimises the mistakes as well as provides me a single location where I need to make changes as we expand or change use.


COMPANY=Example Widgets FAXSPOOL=/var/spool/asterisk/fax/in TIFF2PDF=/usr/local/bin/tiff2pdf FAX2EMAIL=/usr/local/sbin/fax2email.py FAXRCPT=samt@example.com

The paths specified above, need to be created (and the appropriate read/write permissions set)

$ sudo mkdir -p /var/spool/asterisk/fax/in $ sudo chown -R _asterisk:_asterisk /var/spool/asterisk/fax

Incoming Fax Number

To set up our dialplan, we need to specify the “extension” or number that will be taken as an incoming fax call.

[incoming_itsp] exten=> _XXXXXXXX69.,1,NoOP(FAX from ${CALLERID(num)} ${STRFTIME(${EPOCH},,%c)}) same => n,Goto(fax-rcvd,${EXTEN:0:10},1)

We recieve calls on our fax line, display a message on the console and then send execution to the [fax-rcvd] macro.

Fax Receipt Macro

To receive a fax, we:

Note, that with this example we are not doing anything special for transmission (or any other) error.

[fax-rcvd] exten => X.,1,Set(FAXCHANNEL=${CHANNEL:6:-9}) same => n,Set(FAXTIMESTAMP=${STRFTIME(${EPOCH},,%Y-%m-%d%H.%M.%S)}) same => n,Verbose(*** FAXNUMBER ${EXTEN} RECEIPT from ${CALLERID(num)} ${FAXTIMESTAMP} ****) same => n,Set(FAXGUID=${SHELL(/usr/bin/head /dev/random | od -x | head -1 | awk ‘{print $2”-“$3”-“$4”-“$5}’):0:-1}); same => n,Set(FILEPREFIX=${EXTEN}/${CALLERID(num)}on${FAXCHANNEL}${FAXTIMESTAMP}${FAXGUID}) same => n,Set(FAXPATH=${FAXSPOOL}/${FILEPREFIX}) same => n,Set(FAXOPT(ecm)=no) same => n,Set(FAXOPT(headerinfo)=Received by ${COMPANY} ${STRFTIME(${EPOCH},,%Y-%m-%d %H:%M)}) same => n,Set(FAXOPT(localstationid)=${EXTEN}) same => n,Set(FAXOPT(maxrate)=14400) same => n,Set(FAXOPT(minrate)=2400) same => n,System(mkdir -pm 770 ${FAXSPOOL}/${EXTEN}) same => n,ReceiveFAX(${FAXPATH}.tiff) same => n,Set(PDFCONVERSION=${SHELL(${TIFF2PDF} -o ${FAXPATH}.pdf ${FAXPATH}.tiff)}) same => n,System(${FAX2EMAIL} -r ${FAXRCPT} -a ${FAXPATH}.pdf) same => n,Hangup()

Choosing a filename for storing the inbound fax.

We dynamically set the filename from known facts about the fax:


To ensure we don’t get a scenario where two faxes get the same filename, we are also including a random file extension.

same => n,Set(FAXGUID=${SHELL(/usr/bin/head /dev/random | od -x | head -1 | awk ‘{print $2”-“$3”-“$4”-“$5}’):0:-1});

We join our new filename prefix together with the globally defined ${FAXSPOOL} path for our destination file name.


With the above filename convention, a separate directory is used for each fax number. Thus, we have to make sure the full path exists.

same => n,System(mkdir -pm 770 ${FAXSPOOL}/${EXTEN})

and because we are going to do some post-processing of the file, we are going to recieve the file with a file extension of TIFF to represent that Fax transmissions are in G3/TIFF format.

same => n,ReceiveFAX(${FAXPATH}.tiff)


There are two things that we do, as part of fax receipt.

Convert the file to PDF

same => n,Set(PDFCONVERSION=${SHELL(${TIFF2PDF} -o ${FAXPATH}.pdf ${FAXPATH}.tiff)})

Email the file to a recipient

same => n,System(${FAX2EMAIL} -r ${FAXRCPT} -a ${FAXPATH}.pdf)


I found that the biggest problem I had with the fax receipt process, was ensuring that I had the right permissions et. al. with the ${FAX2EMAIL} script, so to be verbose and get some further details on what is happening.

same => n,NoOP(Fax to e-mail: ${SYSTEMSTATUS})

We provide some diagnostic information about the success/failure of the script, from Asterisk’s perspective.

${FAX2EMAIL} Script

Below is the working Python script we use here: