Outgoing Fax Handling

Transmitting faxes from Asterisk is somewhat more difficult than receiving them. The reason for this is simply due to the fact that the preparation of the fax prior to transmission involves more work. There isn’t anything particularly complex about fax transmittal, but you will need to make some design decisions about things like:

Transmitting a Fax from Asterisk

To transmit a fax from Asterisk, you must have a TIFF file. How you generate this TIFF is important, and may involve many steps. However, from Asterisk’s perspective the sending of a fax is fairly straightforward. You simply run the SendFAX() dialplan application, passing it the path to a valid TIFF file:

exten => faxthis,1,SendFAX(/path/to/fax/file,d)

In practice, you will normally want to set some parameters prior to transmission, so a complete extension for sending a fax using Digium’s Fax For Asterisk might look something like this:

exten => faxthis,1,Verbose(2,Set options and transmit fax)

; some folder where your outgoing faxes will be found
  same => n,Set(faxlocation=/tmp) 

; In production you would probably not want to hardcode the filename
  same => n,Set(faxfile=faxfile.tif) 
  same => n,Set(FAXOPT(headerinfo)=Fax from ShiftEight.org)
  same => n,Set(FAXOPT(localstationid=4169671111)
  same => n,SendFax(${faxlocation}/${faxfile})

File Format for Faxing

The real trick of sending a fax is having a source file that is in a format that the fax engine can handle. At a basic level, these files are known as TIFF files; however, the TIFF spec allows for all sorts of parameters, not all of which are compatible with fax and not many of which are documented in any useful way. Additionally, the types of TIFF formats that spandsp can handle are different from those Digium FFA will handle.

In the absence of one simple, clear specification of what TIFF file format will work for sending faxes from Asterisk, we will instead document what we know to work, and leave it up to the reader to perform any experimentation required to find other ways to generate the TIFF.[165]

Digium’s Fax For Asterisk Administration Manual documents a process for converting a PDF file into a TIFF using commonly available Linux command-line tools. While kludgy, this method should allow you to build Linux scripts to handle the file conversion, and your users will be able to submit PDFs as fax jobs.

You will need the ghostscript PDF interpreter, which can be installed in CentOS by the command:

$ sudo yum -y install ghostscript

and in Ubuntu with:

$ sudo apt-get install ghostscript

Once installed, ghostscript can convert the PDF into an Asterisk-compatible TIFF file with the following command:

$ gs -q -dNOPAUSE -dBATCH -sDEVICE=tiffg4 -sPAPERSIZE=letter -sOutputFile=<dest> <src>

Replace <dest> with the name of the output file, and specify the location of your source PDF with <src>.

The ghostscript program should create a TIFF file from your PDF that will be suitable for transmission using Asterisk SendFax().

An Experiment in Email to Fax

Many users would like to be able to send emails as fax documents. The primary challenge with this is ensuring that what the users submit is in a format suitable for faxing. This ultimately requires some form of application development, which is outside the scope of this book.

What we have done is provided a simple example of some methods that at least provide a starting point for delivering email to fax capabilities.

One of the first changes that you would need to make in order to handle this is a change to your /etc/aliases file, which will redirect incoming faxes to an application that can handle them. We are not actually aware of any app that can do this, so you’ll have to write one. The change to your /etc/aliases file would look something like this:

fax:   "| /path/to/program/that/will/handle/incoming/fax/emails"

In our case, Russell built a little Python script called fax.py, so our /etc/aliases file would read something like this:

fax:   "| /asteriskpbx/fax.py"

We have included a copy of the Python script we developed for your reference in Example 19.1, “Proof of concept email to fax gateway, fax.py”. Note that this file is not suitable for production, but merely serves as an example of how a very basic kind of email to fax functionality might be implemented.

Example 19.1. Proof of concept email to fax gateway, fax.py

#!/usr/bin/env python
"""Poor Man's Email to Fax Gateway.

This is a proof of concept email to fax gateway.  There are multiple aspects
that would have to be improved for it to be used in a production environment.

Copyright (C) 2010 - Russell Bryant, Leif Madsen, Jim Van Meggelen
Asterisk: The Definitive Guide
"""

import sys
import os
import email
import base64
import shutil
import socket


AMI_HOST = "localhost"
AMI_PORT = 5038
AMI_USER = "hello"
AMI_PASS = "world"

# This script will pull a TIFF out of an email and save it off to disk to allow
# the SendFax() application in Asterisk to send it.  This is the location on
# disk where the TIFF will be stored.
TIFF_LOCATION = "/tmp/loremipsum.tif"


# Read an email from stdin and parse it.
msg = email.message_from_file(sys.stdin)

# For testing purposes, if you wanted to read an email from a file, you could
# do this, instead.
#try:
#    f = open("email.txt", "r")
#    msg = email.message_from_file(f)
#    f.close()
#except IOError:
#    print "Failed to open email input file."
#    sys.exit(1)

# This next part pulls out a TIFF file attachment from the email and saves it
# off to disk in a format that can be used by the SendFax() application.  This
# part of the script is incredibly non-flexible.  It assumes that the TIFF file
# will be in a specific location in the structure of the message (the second
# part of the payload, after the main body).  Further, it assumes that the
# encoding of the TIFF attachment is base64.  This was the case for the test
# email that we were using that we generated with mutt.  Emails sent by users'
# desktop email clients will vary in _many_ ways.  To be used with user-
# generated emails, this section would have to be much more flexible.
try:
    f2 = open(TIFF_LOCATION, "w")
    f2.write(base64.b64decode(msg.get_payload()[1].get_payload().replace("\n", "")))
    f2.close()
except IOError:
    print "Failed to open file for saving off TIFF attachment."
    sys.exit(1)

# Now that we have a TIFF file to fax, connect to the Asterisk Manager Interface
# to originate a call.
ami_commands = """Action: Login\r
Username: %s\r
Secret: %s\r
\r
Action: Originate\r
Channel: Local/s@sendfax/n\r
Context: receivefax\r
Extension: s\r
Priority: 1\r
SetVar: SUBJECT=%s\r
\r
Action: Logoff\r
\r
""" % (AMI_USER, AMI_PASS, msg['subject'])

print ami_commands

def my_send(s, data):
    """Ensure that we send out the whole data buffer.
    """
    sent = 0
    while sent < len(data):
        res = s.send(data[sent:])
        if res == 0:
            break
        sent = sent + res

def my_recv(s):
    """Read input until there is nothing else to read.
    """
    while True:
        res = s.recv(4096)
        if len(res) == 0:
            break
        print res

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((AMI_HOST, AMI_PORT))
my_send(s, ami_commands)
my_recv(s)
s.shutdown(socket.SHUT_RDWR)
s.close()


We tested this out at a very rudimentary level, and proved the basic concept. If you want to put email to fax into production, you need to understand that you will have more work to do on the application development side in order to deliver something that will actually be robust enough to turn over to an average group of users.



[165] One format we tried was using the Microsoft Office Document Image Writer, which offers “TIFF-monochrome fax” as an output format. This seemed too good to be true, which is exactly what it turned out to be (neither spandsp nor Digium FFA could handle the resulting file). It would have been ideal to have found something common to Windows PCs that could be used by users to “print” an Asterisk-compatible TIFF file.