Automate outbound fax transmission

I think this must have been answered already, but I’m not finding it.

Is there a way that I can set up a cron job on my FreePBX server to send a preformatted fax? I want to send a test fax on a regular basis. An automated process at the other end will receive it and note that it arrived successfully. There’s no need for the fax to change from test to test, so I don’t need any on-the-fly formatting, etc. I’ll just create it once in the proper format, and use it over and over.

I’m hoping there’s a script in Asterisk or FreePBX that I can use to submit the fax, or perhaps a spool directory I can drop an appropriately named and formatted file into to trigger the transmission. Can someone please point me in the right direction?

Thanks, everyone.

Check out “call files”. Create it in another directory and drop it into the /var/spool/asterisk/outgoing/ (?) directory with the file time set to whenever you want it to go. You should be able to automate it to your heart’s content.

I don’t believe there is an easy way to send a fax with a call file in a standard installation.

@cynjut Please expand on your concept as to how to use application sendfax . .

We can call lots of different commands from a call file and I think I had this working for a customer back in '04 or '05.

On the other hand, I could be thinking of an AGI script kicked off by cron that performed the same basic steps - set up the call, identify the target file, and then connect to the outbound to send the fax.

Again, how did you do that back in 2004/5 ?

It’s too late in the day to try to dig that far back.

I’m trying, I really am.

I was using the Free FFA (Fax for Asterisk) module from Digium to queue the faxes up in the call file. There’s an option to run various Asterisk commands from the call file, and IIRC I was using the SendFax command from there.

Of course, that’s been dozens and dozens of Asterisk implementations, and as I recall, it didn’t work very well unless the calls were going out over PRI.

Another possibility is that I was using the command-line sendfax program that FFA used to have.

Or was that Hylafax? Crap, @dicko, I just don’t remember clearly. I know I’ve done this before and it was relatively simple once I had all the options on the command right.

I did a little Googling and this article sure sounds familiar: Asterisk AMI Interface for Faxing

I would add a t38modem (or an IAXmodem) and hylafax(+) , then it becomes somewhat trivial, no call.file or Digium’s “Fax for Asterisk” involved

man sendfax

1 Like

Thank you for the excellent discussion. Call files seem to best fit my needs. I’ve tries setting one up and it initiates the call, but as soon as the other end answers it hangs up. So I’m well on my way, but not there yet. Below are the call files and an excerpt of the log, all hopefully sanitized a bit. Can someone help me across the finish line? Thanks in advance for anything you can do.


Channel: DAHDI/g0/{phone-number}
MaxRetries: 0
RetryTime: 60
WaitTime: 60
Archive: yes
Context: from-internal
Extension: s
Priority: 1
Set: FAXFILE=/root/testfax.tiff
Set: FAXHEADER=Test Fax
Set: TIMESTAMP=2016/12/07 : 16:40:01
Set: DESTINATION={phone-number}
Set: LOCALID={source-number?}
Set: EMAIL={my-e-mail-address}

[15:37:19] WARNING[2491] pbx_spool.c: Unable to set utime on /var/spool/asterisk/outgoing/testfax.call: Operation not permitted
[15:37:19] pbx_spool.c: Attempting call on DAHDI/g0/{phonenumber} for [email protected]:1 (Retry 1)
[15:37:19] sig_pri.c: Requested transfer capability: 0x00 - SPEECH
[15:37:19] dial.c: Called g0/{phonenumber}
[15:37:19] dial.c: DAHDI/i1/{phonenumber}-25d is proceeding
[15:37:19] dial.c: DAHDI/i1/{phonenumber}-25d is making progress
[15:37:34] dial.c: DAHDI/i1/{phonenumber}-25d answered
[15:37:34] pbx.c: Executing [[email protected]:1] Answer("DAHDI/i1/{phonenumber}-25d", "") in new stack
[15:37:34] pbx.c: Executing [[email protected]:2] Wait("DAHDI/i1/{phonenumber}-25d", "1") in new stack
[15:37:35] pbx.c: Executing [[email protected]:3] Macro("DAHDI/i1/{phonenumber}-25d", "user-callerid,") in new stack
[15:37:35] pbx.c: Executing [[email protected]:1] Set("DAHDI/i1/{phonenumber}-25d", "TOUCH_MONITOR={data}.{data}") in new stack
[15:37:35] pbx.c: Executing [[email protected]:2] Set("DAHDI/i1/{phonenumber}-25d", "AMPUSER=") in new stack
[15:37:35] pbx.c: Executing [[email protected]:3] GotoIf("DAHDI/i1/{phonenumber}-25d", "0?report") in new stack
[15:37:35] pbx.c: Executing [[email protected]:4] ExecIf("DAHDI/i1/{phonenumber}-25d", "1?Set(REALCALLERIDNUM=)") in new stack
[15:37:35] pbx.c: Executing [[email protected]:5] Set("DAHDI/i1/{phonenumber}-25d", "AMPUSER=") in new stack
[15:37:35] pbx.c: Executing [[email protected]:6] GotoIf("DAHDI/i1/{phonenumber}-25d", "0?limit") in new stack
[15:37:35] pbx.c: Executing [[email protected]:7] Set("DAHDI/i1/{phonenumber}-25d", "AMPUSERCIDNAME=") in new stack
[15:37:35] pbx.c: Executing [[email protected]:8] GotoIf("DAHDI/i1/{phonenumber}-25d", "1?report") in new stack
[15:37:35] pbx.c: Goto (macro-user-callerid,s,15) 
[15:37:35] pbx.c: Executing [[email protected]:15] GotoIf("DAHDI/i1/{phonenumber}-25d", "0?continue") in new stack 
[15:37:35] pbx.c: Executing [[email protected]:16] ExecIf("DAHDI/i1/{phonenumber}-25d", "1?Set(__CALLEE_ACCOUNCODE=)") in new stack
[15:37:35] pbx.c: Executing [[email protected]:17] Set("DAHDI/i1/{phonenumber}-25d", "__TTL=64") in new stack
[15:37:35] pbx.c: Executing [[email protected]:18] GotoIf("DAHDI/i1/{phonenumber}-25d", "1?continue") in new stack 
[15:37:35] pbx.c: Goto (macro-user-callerid,s,29) 
[15:37:35] pbx.c: Executing [[email protected]:29] Set("DAHDI/i1/{phonenumber}-25d", "CALLERID(number)=") in new stack
[15:37:35] pbx.c: Executing [[email protected]:30] Set("DAHDI/i1/{phonenumber}-25d", "CALLERID(name)=") in new stack
[15:37:35] pbx.c: Executing [[email protected]:31] GotoIf("DAHDI/i1/{phonenumber}-25d", "1?cnum") in new stack
[15:37:35] pbx.c: Goto (macro-user-callerid,s,33) 
[15:37:35] pbx.c: Executing [[email protected]:33] Set("DAHDI/i1/{phonenumber}-25d", "CDR(cnum)=") in new stack 
[15:37:35] WARNING[2444] func_cdr.c: CDR requires a value (CDR(variable)=value)
[15:37:35] pbx.c: Executing [[email protected]:34] Set("DAHDI/i1/{phonenumber}-25d", "CHANNEL(language)=en") in new stack
[15:37:35] pbx.c: Executing [[email protected]:4] GotoIf("DAHDI/i1/{phonenumber}-25d", "0?activate") in new stack 
[15:37:35] pbx.c: Executing [[email protected]:5] GotoIf("DAHDI/i1/{phonenumber}-25d", "0?deactivate:end") in new stack
[15:37:35] pbx.c: Goto (from-internal,s,10)
[15:37:35] pbx.c: Executing [[email protected]:10] Macro("DAHDI/i1/{phonenumber}-25d", "hangupcall,") in new stack
[15:37:35] pbx.c: Executing [[email protected]:1] GotoIf("DAHDI/i1/{phonenumber}-25d", "1?theend") in new stack
[15:37:35] pbx.c: Goto (macro-hangupcall,s,3)
[15:37:35] pbx.c: Executing [[email protected]:3] ExecIf("DAHDI/i1/{phonenumber}-25d", "0?Set(CDR(recordingfile)=)") in new stack
[15:37:35] pbx.c: Executing [[email protected]:4] Hangup("DAHDI/i1/{phonenumber}-25d", "") in new stack
[15:37:35] app_macro.c: Spawn extension (macro-hangupcall, s, 4) exited non-zero on 'DAHDI/i1/{phonenumber}-25d' in macro 'hangupcall'
[15:37:35] pbx.c: Spawn extension (from-internal, s, 10) exited non-zero on 'DAHDI/i1/{phonenumber}-25d'
[15:37:35] pbx.c: Executing [[email protected]:1] Macro("DAHDI/i1/{phonenumber}-25d", "hangupcall") in new stack 
[15:37:35] pbx.c: Executing [[email protected]:1] GotoIf("DAHDI/i1/{phonenumber}-25d", "1?theend") in new stack
[15:37:35] pbx.c: Goto (macro-hangupcall,s,3)
[15:37:35] pbx.c: Executing [[email protected]:3] ExecIf("DAHDI/i1/{phonenumber}-25d", "0?Set(CDR(recordingfile)=)") in new stack
[15:37:35] pbx.c: Executing [[email protected]:4] Hangup("DAHDI/i1/{phonenumber}-25d", "") in new stack
[15:37:35] app_macro.c: Spawn extension (macro-hangupcall, s, 4) exited non-zero on 'DAHDI/i1/{phonenumber}-25d' in macro 'hangupcall'
[15:37:35] pbx.c: Spawn extension (from-internal, h, 1) exited non-zero on 'DAHDI/i1/{phonenumber}-25d'
[15:37:35] chan_dahdi.c: Hungup 'DAHDI/i1/{phonenumber}-25d'

Tht doesn’t seem right, at least not for “from-internal”. It’s hanging up the phone as soon as it gets there, so something in the “from-internal” part (like your internal extension number?) is making it unhappy.

Sorry for the horribly long delay responding. I got pulled off this project to work on other tasks, and just got back to it. (I’m sure that’s never happens to any of you. ;-)).

With Dave and dicko’s valuable help, more research, and some trial and error, I got this all working. Here’s the call file I’m using (sensitive data changed to dummy values, of course.)

Channel: DAHDI/g0/1112223333
MaxRetries: 0
RetryTime: 60
WaitTime: 60
Archive: no
Context: send-fax
Extension: 444
Priority: 1
Application:SendFAX
Data: /usr/local/etc/faxe2e/faxe2e.tiff

Replace 1112223333 with the target phone number, 444 with the origin extension, and correct the “Data:” entry to point to your tiff or pdf image. There is probably some room for improvement here. I don’t know that the “Extension: 444” actually does anything. I also don’t know how to specify the origin station ID or station name, though these aren’t critical for my purposes. With this call file, I can automate fax delivery, which was my objective.

I’ll wrap up with a bit about why I wanted to do this, as my technique might be useful to others. Unfortunately, we rely on faxes heavily. It’s not our choice – more of an industry norm amongst our clients that we have to support. We have had some problems with faxes not going out or coming in properly. FreePBX accepts the faxes, but then an e-mail delivery problem on inbound faxes, or similar stuck-queue issue on outbound faxes prevents them from actually getting to the desired destination. Needless to say, this causes frustration amongst our staff and makes us look bad to clients. Part of my solution is to resolve the root problem of course, but another is make sure we’re alerted if a problem happens again. I try to never fix an single problem if I can fix a whole class of problems instead.

I’ve implemented the following to automatically detect when faxes, either inbound or outbound, are not being delivered properly.

  1. A cronjob submits the above call file every four hours. (Could be every 30 minutes, whatever is appropriate.)
  2. The call file is used to send a canned fax to a canned external phone number.
  3. The external phone number is actually one of our own external phone numbers, so the fax goes out through our regular outbound trunk, to the telco, and then comes back in on the designated number. This tests both outbound and inbound transmission.
  4. The external phone number is dedicated to this purpose, and its has a special e-mail delivery address.
  5. The mail system has an alias for this address that just captures the e-mail and overwrites a file with it. This is primarily for diagnostics if a problem arises. Simply touching the file would be sufficient.
  6. My regular monitoring routines check the modification time stamp on the file on a regular basis. If it hasn’t updated in a reasonable time (e.g. 4 hours), an alert goes out indicating that there is a problem with fax delivery.

I got here with the help of others, like Dave and dicko. Hopefully this will help someone in the future.