Faxempfang auf Asterisk mit und ohne E-Mail-Weiterleitung als TIFF oder PDF

2.4.2024 (9.4.2024 zuletzt ergänzt und überarbeitet)

Der Faxempfang lässt sich in Asterisk mit ein paar Programmzeilen umsetzen. Viel Komfort bietet die Lösung noch nicht. Sie ist aber einfach zu verstehen und beliebig ausbaufähig. Getestet wurde mit Asterisk 16 auf einem Raspberry Pi  3 B. Wir müssen nur in Asterisk in der sip.conf und in der extensions.conf  ein paar Zeilen hinzufügen und noch einen Ordner anlegen und freigeben, in welchem die Faxeinrichtung die Faxe als TIFF-Dateien ablegt. Anschließend gibt es noch eine Lösung mit einer E-Mail-Weiterreichung der Faxe als TIFF oder PDF. ChatGPT hat mir bei der Entwicklung sehr geholfen und sollte bei weiteren Fragen konsultiert werden. Voraussetzung für das Verständnis dieses Artikels ist es,  dass wir bereits einen Asteriskserver auf unserem Raspberry Pi zum Laufen gebracht haben. Grundkenntnisse in Linux sollten auch bestehen.

Ein Raspberry Pi 3 reicht für die Hardware völlig aus.

Dieser Artikel beschreibt Etappenziele, die immer komfortabler werden. In der ersten Stufe legt der Asterisk-Fax-Empfänger die empfangenen Faxe als TIFF-Dateien in einem Ordner ab. In der zweiten Stufe werden diese TIFF-Dateien mit einem Python-Programm oder von Asterisk als E-Mail-Anhänge verschickt. Dazu kommt das E-Mail-Programm MUTT zum Einsatz. Im dritten und letzten Schritt werden die TIFF-Dateien vor dem E-Mailversand in PDF-Dateien umgewandelt. Die Umwandlung erledigt das Programm ImageMagick. Alles geschieht auf einem Raspberry Pi 3 B unter Raspbian, das einem Debian-Linux entspricht.

Der Asterisk-Telefonserver auf dem kleinen Raspberry Pi leitet die empfangenen Faxe als PDF per E-Mail weiter.

ChatGPT: Eine große Hilfe dabei war für mich ChatGPT. Die KI hat nach meinen Anweisungen die Python-Skripte geschrieben, die entsprechenden Programme empfohlen und mir dabei geholfen sie richtig zu konfigurieren. Allerdings hat ChatGPT einige Dinge falsch behauptet, die ich selbst herausfinden musste. Dann ist ChatGPT überhaupt nicht kreativ, wenn es um alternative Lösungsansätze geht. Die grundlegende Struktur von Python muss man kennen und man sollte schon ein paar einfache Pythonskripte geschrieben haben. Leider konnte mir ChatGPT nicht dabei helfen ohne Python auszukommen. Auch kann ChatGPT auf einen Schlag keine vollständige Lösung anbieten. Besser ist es sich Schritt für Schritt von einer primitiven Lösung zu einer komplexen Lösung heranzutasten, um Fehlerquellen ausschließen zu können. Der Lerneffekt dabei ist der größte Bonus. Das Lernen geht viel schneller, da man nicht mehr viel Zeit mit dem unproduktiven Suchen im Internet verschwendet. Wichtig bei der Kommunikation mit ChatGPT ist eine eindeutige, strukturierte, unmissverständliche und prägnante Ausdrucksweise. Schwammige Formulierungen versteht ChatGPT falsch.

Schritt für Schritt erklärt: Zuerst müssen wir in Asterisk eventuell die sip.conf vorbereiten und unter [general] folgendes eingetragen haben:

faxdetect=yes ; kann auch auf no stehen.
; t38pt_udptl=yes
; directmedia=no

T.38 habe ich leider nicht zum Laufen gebracht. Es darf auch nicht in der sip.conf aktiviert werden bei meiner Konfiguration.

Und schließlich müssen wir noch die extensions.conf ergänzen. Für den Faxempfang ist das Macro Faxempfang zuständig:

; Faxempfang
[macro-faxempfang]
exten => s,1,NoOp("Empfang eines Faxes")
 same => n,Set(FAXOPT(ecm)=yes)
 same => n,Set(FAXOPT(headerinfo)=Ankommendes Fax)
 same => n,ReceiveFax(/var/spool/asterisk/fax/incoming/${UNIQUEID}.tif)
 same => n,Hangup()

Die ankommenden Faxe werden als TIFF-Dateien im Verzeichnis /var/spool/asterisk/fax/incoming/ abgelegt. Wichtig ist, dass der Ordner Schreib- und Leseberechtigungen hat. Den Ordner müssen wir von Hand anlegen. Die empfangenen Faxe landen in dieser rudimentären Version noch ohne Empfangshinweise in diesem Ordner. Wer uns ein Fax schickt, muss das also ankündigen. Ich schaue in den Ordner über FileZilla rein, um von Windows auf den Raspberry Pi zugreifen zu können, auf dem sich Asterisk befindet. Es ist eine spartanische Lösung, die aber oft ausreichend ist.

Dieses Macro müssen wir noch mit einer Telefonnummer (Wahlregel in der extensions.conf) verknüpfen, damit das Fax überhaupt angerufen werden kann. In der extensions.conf steht deshalb folgendes:

; Faxempfang
exten => 1093,1,Noop(Faxempfang Asterisk 1093 - "${CALLERID(name)}" <${CALLERID(num)}>) 
 same => n,Set(SIP_CODEC=g722) ; optional
 same => n,Answer()
 same => n,Macro(faxempfang)
 same => n,Hangup()

Wählt also jemand hier im Beispiel die 1093, dann wird das Macro Faxempfang aufgerufen und Asterisk kann ein Fax empfangen.

Folgendes meldet die Asterisk-Konsole nach dem Empfang eines Faxes:

 -- Executing [1093@j:1] NoOp("SIP/1099-0000018d", "Rufannahme für Faxnummer 1093") in new stack
    -- Executing [1093@j:2] Answer("SIP/1099-0000018d", "") in new stack
    -- Executing [1093@j:3] Macro("SIP/1099-0000018d", "faxempfang") in new stack
    -- Executing [s@macro-faxempfang:1] NoOp("SIP/1099-0000018d", ""Empfang eines Faxes"") in new stack
    -- Executing [s@macro-faxempfang:2] Set("SIP/1099-0000018d", "FAXOPT(ecm)=yes") in new stack
    -- Executing [s@macro-faxempfang:3] Set("SIP/1099-0000018d", "FAXOPT(headerinfo)=Ankommendes Fax") in new stack
    -- Executing [s@macro-faxempfang:4] ReceiveFAX("SIP/1099-0000018d", "/var/spool/asterisk/fax/incoming/1712066173.680.tif") in new stack
    -- Channel 'SIP/1099-0000018d' receiving FAX '/var/spool/asterisk/fax/incoming/1712066173.680.tif'
[2024-04-02 15:56:14] WARNING[30777][C-000000f2]: chan_sip.c:10683 process_sdp: Failed to initialize UDPTL, declining image stream
[2024-04-02 15:56:14] WARNING[30777][C-000000f2]: chan_sip.c:10870 process_sdp: Failing due to no acceptable offer found
[2024-04-02 15:56:14] NOTICE[21506][C-000000f2]: chan_sip.c:8739 sip_read: FAX CNG detected but no fax extension
[2024-04-02 15:56:42] WARNING[21506][C-000000f2]: res_fax_spandsp.c:438 spandsp_log: WARNING T.30 ECM carrier not found
    -- Executing [s@macro-faxempfang:5] Hangup("SIP/1099-0000018d", "") in new stack
  == Spawn extension (macro-faxempfang, s, 5) exited non-zero on 'SIP/1099-0000018d' in macro 'faxempfang'
  == Spawn extension (janson, 1093, 3) exited non-zero on 'SIP/1099-0000018d'

Die Faxe schaue ich mir bequemerweise in Windows  über Filezilla an:

Filezilla ermöglicht den Zugriff von einem anderen Rechner auf den Raspberry. Auf diese einfache Weise kann ich die eingegangenen Faxe auf meinem Windows-Rechner betrachten, kopieren und drucken.

Variante mit Zeitstempeln: Die Dateinamen der empfangenen Dateien lassen das Empfangsdatum erkennen, wenn man das Macro etwas abändert:

[macro-faxempfang]
exten => s,1,Noop(Faxempfang Asterisk 1093 - "${CALLERID(name)}" <${CALLERID(num)}>) 
 same => n,Set(FAXOPT(ecm)=yes)
 same => n,Set(FAXOPT(headerinfo)=Ankommendes Fax)
; die empfangenen Faxe landen im Ordner /var/spool/asterisk/fax/incoming
 same => n,Set(FAXDEST=/var/spool/asterisk/fax/incoming) 
; put a timestamp on this call so the resulting file is unique
 same => n,Set(tempfax=${STRFTIME(,,%C%y%m%d%H%M)}) 
 same => n,ReceiveFax(${FAXDEST}/${tempfax}.tif)
 same => n,Verbose(3,- Fax receipt completed with status: ${FAXSTATUS})
 same => n,Hangup()

Wer will kann diesen einfachen Faxempfänger erweitern und die Faxe an eine E-Mail-Adresse schicken lassen. Meine FritzBox erledigt dies bereits und deshalb war meine Motivation  noch gering. Weiter unten im Text ist meine E-Mail-Lösung beschrieben.

Zum Testen wurden die Faxe vom Softphone-Fax VentaFax und von einem über 30 Jahre alten mechanischen Fax verschickt. Mit VentaFax lassen sich per Mausklick sehr bequem Faxe verschicken, was bei der Fehlersuche hilfreich ist.

Das über 30 Jahre alte Minoltafax 160 dient zum Verschicken von Faxen und als Scanner.
Zum Senden und Empfangen von Faxen kommt testweise auch das SIP-Softphone-Fax VentaFax unter Windows zum Einsatz. Es eignet sich wunderbar zum Experimentieren und ein SIP-Account lässt sich eintragen.

E-Mailweiterleitung der Faxe einrichten: Wenn ein Fax eintrudelt, soll es als TIFF-Datei per E-Mail weitergeleitet werden.

Dazu müssen wir auf dem Raspberry (oder Linux) ein E-Mail-Programm installieren und konfigurieren. Hierfür eignet sich Mutt, da es auf der Kommandozeilenebene arbeitet.

Installation von Mutt auf dem Raspberry:

sudo apt-get update
sudo apt-get install mutt

Konfiguration von Mutt für die Versendung von E-Mails: Dazu müssen wir von Hand eine Datei .muttrc im Home-Verzeichnis anlegen. Wir nehmen das Home-Verzeichnis, in dem sich das Mutt und das Asterisk befindet. Die .muttrc-Datei wird normalerweise im Home-Verzeichnis des Benutzers abgelegt, der Mutt verwenden wird. Die Datei steuert die Konfigurationseinstellungen von Mutt, daher sollte sie im Home-Verzeichnis des Benutzers liegen, der Mutt verwendet. Wenn wir nicht sicher sind, können wir sie kopieren und in ein weiteres Home-Verzeichnis unterbringen. Dieser Datei vergeben wir solche Rechte, damit sie von allen gelesen werden kann.

Inhalt und Konfiguration der .muttrc: Hier am Beispiel eine E-Mail, die von Strato gehostet wird.

set from = "hans.mustermann@mustermann.de"
set realname = "Hans Mustermann"
set smtp_url = "smtps://hans.mustermann@mustermann.de:passwort@smtp.strato.de:465/"

set spoolfile = "/var/spool/asterisk/fax/incoming"
set folder = "/var/spool/asterisk/fax/incoming"
set mask = ".*"
mailboxes +INBOX

Hier im Beispiel habe ich eine fiktive hans.mustermann@mustermann.de eingetragen, die wie bereits erwähnt bei Strato gehostet ist. Der von Hand anzulegende Pfad /var/spool/asterisk/fax/incoming beschreibt den Ort, in welchem Asterisk die Faxe als TIFF-Dateien ablegt.

Wir können mit einem Befehl testen, ob die Konfiguration für das Versenden von E-Mails korrekt ist:

echo "Testnachricht von Mutt" | mutt -s "Test-E-Mail" beispiel@beispiel.de

Die beispiel@beispiel.de ist durch eine real existierende E-Mail-Adresse zu ersetzen.

Jetzt müssen wir noch das Macro für den Faxempfang abändern:

; Faxempfang
[macro-faxempfang]
exten => s,1,Noop(Faxempfang Asterisk 1093 - "${CALLERID(name)}" <${CALLERID(num)}>) 
 same => n,Set(FAXOPT(ecm)=yes)
 same => n,Set(FAXOPT(headerinfo)=Ankommendes Fax)
 same => n,Set(FAXDEST=/var/spool/asterisk/fax/incoming) 

; put a timestamp on this call so the resulting file is unique
  same => n,Set(tempfax=${STRFTIME(,,%C%y%m%d%H%M)}) 
  same => n,ReceiveFax(${FAXDEST}/${tempfax}.tif)
  same => n,Verbose(3,- Fax receipt completed with status: ${FAXSTATUS})
  same => n,System(echo "Du hast ein Fax erhalten. Siehe Anhang." | mutt -s "Faxempfang vom Asterisk-Server" beispiel@beispiel.de -a "${FAXDEST}/${tempfax}.tif")
  same => n,Hangup()

Die E-Mails gelangen mit dem Fax-Anhang als TIFF an beispiel@beispiel.de. Theoretisch müsste es funktionieren. Bei mir hat es allerdings nicht geklappt das System zu veranlassen Faxe aus Asterisk zu verschicken. Es kann an meiner Version von Raspbian und/oder meiner Asterisk-Version 16.2 liegen. Nach einem Tag Sucherei und Ausprobieren habe ich aufgeben und bin zu einer anderen Lösung gekommen, die einen anderen Weg geht und unabhängig von Asterisk arbeitet.

Alternative mit einem Python-Skript: Dieses Skript läuft ewig und prüft alle 120 Sekunden den Ordner /var/spool/asterisk/fax/incoming auf neue Dateien, die dann dann mit Mutt versendet werden und dann gelöscht.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import time
import subprocess

def send_email(subject, recipient, file_path):
    # Befehl zum Versenden der E-Mail mit Mutt
    command = 'echo "Fax erhalten. Es befindet sich als Anhang als TIF-Datei." | /usr/bin/mutt -s "{}" {} -a {}'.format(subject, recipient, file_path)
    os.system(command)

def watch_directory(directory):
    file_dict = {}  # Ein Wörterbuch zum Verfolgen der Dateigrößen
    while True:
        for filename in os.listdir(directory):
            if filename.endswith(".tif"):  # Wenn eine TIF-Datei gefunden wird
                file_path = os.path.join(directory, filename)
                file_size = os.path.getsize(file_path)
                if filename not in file_dict:  # Neue Datei gefunden
                    file_dict[filename] = file_size
                elif file_size != file_dict[filename]:  # Datei hat sich geändert
                    time.sleep(60)  # Warten, um sicherzustellen, dass die Datei fertig geladen ist
                    # Überprüfen, ob die Dateigröße stabil bleibt
                    new_file_size = os.path.getsize(file_path)
                    if new_file_size == file_size:  # Datei ist stabil, kann verschickt werden
                        # E-Mail senden
                        send_email("Faxempfang vom Asterisk-Server", "max@mustermann.de", file_path)
                        # Datei löschen
                        os.remove(file_path)
                        del file_dict[filename]
                    else:
                        file_dict[filename] = new_file_size

        time.sleep(120)  # Wartezeit zwischen den Überprüfungen

if __name__ == "__main__":
    directory_to_watch = "/var/spool/asterisk/fax/incoming/"
    watch_directory(directory_to_watch)

Wir müssen dieses Skript einmalig starten. Ich habe es fax60.py genannt und in /usr/share/asterisk/agi-bin/fax60.py untergebracht.

So startet man es:

sudo python /usr/share/asterisk/agi-bin/fax60.py

Wir starten das Programm in einem eigenen Fenster, damit wir es mit der Tastaturkombination Strg + C beenden können. Mit dem Befehl „top“ habe keine zusätzliche Belastung der CPU durch dieses im Hintergrund laufende Python-Skript feststellen können.

Wenn wir die Datei unter Windows editiert haben, müssen wir sie einmalig noch konvertieren und die Rechte vergeben:

sudo dos2unix /usr/share/asterisk/agi-bin/fax60.py
sudo chmod 777 /usr/share/asterisk/agi-bin/fax60.py
sudo python /usr/share/asterisk/agi-bin/fax60.py

Die TIFF-Dateien können unter Windows mit IrfanView betrachtet werden. Unter Android kommt dafür die App „Multi-TIFF-Viewer“ zum Einsatz.

Leider kam bei mehrseitigen Faxen mit dieser Lösung durch den E-Mailversand nur die erste Seite bei mehrseitigen Faxen an.

Ein- und mehrseitige Faxe per E-Mail als PDF verschicken: Das ist die nächste Ausbaustufe. Für die Umwandlung von TIFF nach PDF dient das Programm ImageMagick, das wie folgt zu installieren ist:

sudo apt update
sudo apt install imagemagick

Leider müssen wir noch händisch eine Sicherheitseinstellung von ImageMagick verändern. Öffne dazu die Datei

/etc/ImageMagick-6/policy.xml

in einem Texteditor. Suche nach einer Zeile, die die Sicherheitsrichtlinie für das PDF-Format festlegt. Es könnte etwas wie das Folgende aussehen:

<policy domain="coder" rights="none" pattern="PDF" />

Ändere  none auf read | write, um die Berechtigungen für das PDF-Format zu erweitern:

<policy domain="coder" rights="read | write" pattern="PDF" />

Dann klappt das Konvertieren der TIFF-Dateien auf PDF-Dateien.

Ein Python-Skript sucht nach einer neu eingetroffen TIFF-Datei. Es wartet einige Minuten, bis sie vollständig geladen ist, wandelt die TIFF nach PDF um und versendet die PDF als E-Mail-Anhang mit dem E-Mailprogramm MUTT. Danach werden die beiden Dateien gelöscht und das Spiel fängt von vorne in einer Endlosschleife an. Diese Schleife können wir mit der Tastaturkombination Strg + C abbrechen.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import time
import subprocess

def wait_for_stable_size(file_path, interval=10, stable_period=180, min_size=10240):
    """
    Überprüft regelmäßig die Größe der Datei und stellt sicher, dass sie für eine bestimmte Zeit stabil bleibt und eine Mindestgröße hat.
    :param file_path: Pfad zur Datei
    :param interval: Zeitintervall in Sekunden zwischen den Überprüfungen der Dateigröße
    :param stable_period: Zeitdauer in Sekunden, während der die Dateigröße stabil sein muss
    :param min_size: Mindestgröße der Datei, die als vollständig geladen betrachtet wird
    """
    initial_size = os.path.getsize(file_path)
    stable_counter = 0
    while stable_counter < stable_period // interval:
        current_size = os.path.getsize(file_path)
        if current_size >= min_size:
            if current_size == initial_size:
                stable_counter += 1
            else:
                stable_counter = 0
        else:
            stable_counter = 0
        initial_size = current_size
        time.sleep(interval)


def convert_to_pdf(tif_file):
    """
    Konvertiert die TIFF-Datei in eine PDF-Datei und gibt den Pfad zur PDF-Datei zurück.
    :param tif_file: Pfad zur TIFF-Datei
    :return: Pfad zur PDF-Datei
    """
    pdf_file = os.path.splitext(tif_file)[0] + ".pdf"
    command = "convert {} {}".format(tif_file, pdf_file)
    subprocess.call(command, shell=True)
    return pdf_file

def send_email(subject, recipient, file_path):
    """
    Sendet eine E-Mail mit der angegebenen Betreffzeile, Empfänger und Datei als Anhang.
    :param subject: Betreff der E-Mail
    :param recipient: E-Mail-Adresse des Empfängers
    :param file_path: Pfad zur Datei, die als Anhang gesendet werden soll
    """
    # Befehl zum Versenden der E-Mail mit Mutt
    command = 'echo "Fax als PDF im Anhang erhalten." | /usr/bin/mutt -s "{}" {} -a {}'.format(subject, recipient, file_path)
    os.system(command)

def watch_directory(directory):
    """
    Überwacht das angegebene Verzeichnis auf neue TIFF-Dateien und führt bei Bedarf die Konvertierung und den E-Mail-Versand durch.
    :param directory: Pfad zum zu überwachenden Verzeichnis
    """
    while True:
        for filename in os.listdir(directory):
            if filename.endswith(".tif"):  # Wenn eine TIF-Datei gefunden wird
                file_path = os.path.join(directory, filename)
                print("TIFF-Datei wird empfangen.")
                # Warten, bis die Dateigröße stabil ist
                wait_for_stable_size(file_path)
                print("PDF wird erstellt...")
                # Konvertiere TIF in PDF
                pdf_file = convert_to_pdf(file_path)
                print("PDF-Datei erfolgreich erstellt.")
                print("E-Mail wird verschickt...")
                # Warten, bis die PDF-Datei vollständig geladen ist
                wait_for_stable_size(pdf_file)
                # E-Mail senden
                send_email("Faxempfang vom Asterisk-Server", "max.mustermann@mustermann.de", pdf_file)
                print("PDF als E-Mail verschickt.")
                # Dateien löschen
                os.remove(file_path)
                os.remove(pdf_file)
                print("PDF- und TIFF-Datei wurden gelöscht.")
        time.sleep(120)  # Wartezeit zwischen den Überprüfungen

if __name__ == "__main__":
    directory_to_watch = "/var/spool/asterisk/fax/incoming/"
    watch_directory(directory_to_watch)

Auf meinem Android-Smartphone lassen sich die PDF mit ReadEra lesen.

Verbesserte Version des Macros für den Faxempfang: Es werden 5 Verbindungsversuche unternommen, bis zum Auflegen. Außerdem zeigt das Macro Informationen über den Faxversand und den Faxstatus an.

; Faxempfang
[macro-faxempfang]
exten => s,1,Noop(Faxempfang auf Asterisk von "${CALLERID(name)}" <${CALLERID(num)}>)
 same => n,Set(FAXOPT(ecm)=yes)                           ; ECM-Fehlerkorrektur
 same => n,Set(TRYCOUNT=0)                                ; Initialisieren der Versuchsanzahl
 same => n,Set(FAXDEST=/var/spool/asterisk/fax/incoming)  ; Pfad empfangener TIFFs
 same => n,Set(tempfax=${STRFTIME(,,%C%y%m%d%H%M)})       ; vergibt der TIFF Namen mit Zeitangabe
 same => n(label),ReceiveFax(${FAXDEST}/${tempfax}.tif)   ; TIFF empfangen, wenn möglich
 same => n,NoOp(STATUS: ${FAXOPT(status)})                ; Info, ob erfogreich oder gescheiterer Faxversand
 same => n,NoOp(RESOLUTION: ${FAXOPT(resolution)})        ; Auflösung des Fax
 same => n,NoOp(RATE: ${FAXOPT(rate)})                    ; Geschwindigkeit
 same => n,NoOp(PAGES: ${FAXOPT(pages)})                  ; Anzahl übertragener Seiten
 same => n,NoOp(ERROR: ${FAXOPT(error)})                  ; Fehlermeldung
  
; Verschiedene optionale Alternativen für den E-Mailversand (Siehe Text im Artikel)  
; same => n,AGI(/usr/share/asterisk/agi-bin/faxempfangemail.py)
; same => n,System(python /usr/share/asterisk/agi-bin/faxempfangemail.py)
; same => n,System(echo "Du hast ein Fax erhalten. Siehe Anhang." | mutt -s "Faxempfang vom Asterisk-Server" max@mustermann.de -a "${FAXDEST}/${tempfax}.tif")

  same => n,Set(TRYCOUNT=$[${TRYCOUNT} + 1])               ; Weiterer Verbindungsversuch
  same => n,GotoIf($[${TRYCOUNT} < 5]?label)               ; 5 Verbindungsversuche bis zum Auflegen
  same => n,Hangup()                                       ; Auflegen

Vorschlag von ChatGPT für den PDF-Versand ohne Python-Skript: Dieses Macro konnte ich leider nicht auf meinem System testen. E-Mail-Programm Mutt und und Konvertierungsprogramm ImageMagick müssen bereits installiert und konfiguriert sein wie im Text bereits beschrieben. Das Macro unternimmt maximal 5 Verbindungsversuche bevor es die Verbindung aufgibt und unterbricht.

; Faxempfang
[macro-faxempfang]
exten => s,1,Noop(Faxempfang auf Asterisk von "${CALLERID(name)}" <${CALLERID(num)}>)
 same => n,Set(FAXOPT(ecm)=yes)                           ; ECM-Fehlerkorrektur
 same => n,Set(TRYCOUNT=0)                                ; Initialisieren der Versuchsanzahl
 same => n,Set(FAXDEST=/var/spool/asterisk/fax/incoming)  ; Pfad empfangener TIFFs
 same => n,Set(tempfax=${STRFTIME(,,%C%y%m%d%H%M)})       ; vergibt der TIFF Namen mit Zeitangabe
 same => n(label),ReceiveFax(${FAXDEST}/${tempfax}.tif)   ; TIFF empfangen, wenn möglich
 same => n,NoOp(STATUS: ${FAXOPT(status)})                ; Info, ob erfogreich oder gescheiterer Faxversand
 same => n,NoOp(RESOLUTION: ${FAXOPT(resolution)})        ; Auflösung des Fax
 same => n,NoOp(RATE: ${FAXOPT(rate)})                    ; Geschwindigkeit
 same => n,NoOp(PAGES: ${FAXOPT(pages)})                  ; Anzahl übertragener Seiten
 same => n,NoOp(ERROR: ${FAXOPT(error)})                  ; Fehlermeldung

 ; TIFF nach PDF konvertieren
 same => n,System(convert ${FAXDEST}/${tempfax}.tif ${FAXDEST}/${tempfax}.pdf)
 
 ; E-Mail mit PDF-Anhang versenden
 same => n,System(echo "Du hast ein Fax erhalten. Siehe Anhang." | mutt -s "Faxempfang vom Asterisk-Server" max@mustermann.de -a "${FAXDEST}/${tempfax}.pdf")

 ; TIFF- und PDF-Dateien löschen
 same => n,System(rm ${FAXDEST}/${tempfax}.tif)
 same => n,System(rm ${FAXDEST}/${tempfax}.pdf)

 same => n,Set(TRYCOUNT=$[${TRYCOUNT} + 1])               ; Weiterer Verbindungsversuch
 same => n,GotoIf($[${TRYCOUNT} < 5]?label)               ; 5 Verbindungsversuche bis zum Auflegen
 same => n,Hangup()                                       ; Auflegen

Das Skript habe ich ausprobiert. TIFFs kommen im Ordner an. Die Umwandlung von TIFF nach PDF erfolgt. Aber es tritt wieder das alte und anscheinend unlösbare Problem auf, dass sich das E-Mail-Programm Mutt nicht von Asterisk heraus aktivieren lässt.

Verschicken von Faxen per E-Mail mit Mutt als TIFF-Datei ohne Python-Skript: Der Durchbruch. Endlich ist es mir gelungen, dass der Befehl zum Verschicken von E-Mails mit Mutt direkt von Asterisk erfolgen kann. Dazu muss eine Kopie der bereits erwähnten Datei .muttrc in den Ordner /var/lib/asterisk/ oder /home/asterisk/ kopiert werden. Bei meiner Asterisk-Version 16 war es /var/lib/asterisk/. Dieser Datei .muttrc habe ich alle Berechtigungen noch vergeben, damit sie jeder verändern und lesen kann.

Damit die Änderung durch das Umkopieren der .muttrc wirksam wird, muss Asterisk neu gestartet werden:

sudo systemctl restart asterisk
Endlich mit Mutt direkt aus extensions.conf von Asterisk faxen können, nachdem die .muttrc nach /var/lib/asterisk kopiert wurde und dieser Datei alle Berechtigungen zugeteilt wurden.

Nachfolgend die Wahlregel in der extensions.conf für das Anrufen des Faxes mit der Nummer 1094: Damit lassen sich die Faxe als TIFF-Anhänge per E-Mail verschicken.

; Faxempfang auf der Nummer 1094 mit E-Mail-Weiterleitung und TIFF als Anhang

; Damit dieses Skript funktioniert, ist die konfigurierte .muttrc für Asterisk 16
; in den Ordner var/lib/asterisk/ oder bei anderen Versionen eventuell nach /home/asterisk/ zu kopieren.
; Der .muttrc alle Rechte für jeden vergeben.
; Nach dem Kopieren der .muttrc muss Asterisk mit
; sudo systemctl restart asterisk neu gestartet werden, damit die Änderung wirksam wird.

; Die empfangenen TIFF-Dateien sind im Ordner /var/spool/asterisk/fax/incoming untergebracht.
; Dieser Ordner ist mit Schreib-Leserechten für jeden Benutzer anzulegen.
; Als eindeutigen Namen erhalten die TIFF einen Zeitstempel.
; Nach fünf vergeblichen Verbindungsversuchen legt das Fax auf.
; Die E-Mail mit dem TIFF-Anhang wird als Beispiel an max@mustermann.de geschickt
; Die empfangenen TIFF-Dateien werden leider nicht automatisch gelöscht.
 
  
 exten => 1094,1,Noop(Faxempfang 1094 Asterisk-Server von "${CALLERID(name)}" <${CALLERID(num)}>)
  same => n,Set(SIP_CODEC=g722)
  same => n,Answer()
  same => n,Set(FAXOPT(ecm)=yes)                           ; ECM-Fehlerkorrektur
  same => n,Set(TRYCOUNT=0)                                ; Initialisieren der Versuchsanzahl
  same => n,Set(FAXDEST=/var/spool/asterisk/fax/incoming)  ; Pfad empfangener TIFFs
  same => n,Set(tempfax=${STRFTIME(,,%C%y%m%d%H%M)})       ; vergibt der TIFF Namen mit Zeitangabe
  same => n(label),ReceiveFax(${FAXDEST}/${tempfax}.tif)   ; TIFF empfangen, wenn möglich
    
  ; same => n,System(convert ${FAXDEST}/${tempfax}.tif ${FAXDEST}/${tempfax}.pdf) ; Geht nicht, da Asterisk nur ein System- oder AGI-Befehl verarbeiten kann.
  same => n,System(echo "Sie haben von "${CALLERID(name)}" <${CALLERID(num)}> ein Fax erhalten. Sie finden das Fax als TIFF-Datei im  Anhang. Mehrseitige TIFF-Dateien lassen sich mit IrfanView unter Windows oder dem Multi-TIFF Viewer unter Android betrachten." | mutt -s "Faxnachricht via SM5ZBS-Asterisk-Server erhalten" max@mustermann.de -a "${FAXDEST}/${tempfax}.tif")

  same => n,NoOp(STATUS: ${FAXOPT(status)})                ; Info, ob erfolgreich oder gescheiterer Faxversand
  same => n,NoOp(RESOLUTION: ${FAXOPT(resolution)})        ; Auflösung des Fax
  same => n,NoOp(RATE: ${FAXOPT(rate)})                    ; Geschwindigkeit der Übertragung
  same => n,NoOp(PAGES: ${FAXOPT(pages)})                  ; Anzahl übertragener Seiten
  same => n,NoOp(ERROR: ${FAXOPT(error)})                  ; Fehlermeldung der Übertragung

  same => n,Set(TRYCOUNT=$[${TRYCOUNT} + 1])               ; Weiterer Verbindungsversuch
  same => n,GotoIf($[${TRYCOUNT} < 5]?label)               ; 5 Verbindungsversuche bis zum Auflegen
  same => n,Hangup()                                       ; Auflegen

Tja, wenn ich darauf früher gekommen wäre. Leider funktioniert die Umwandlung von TIFF nach PDF nicht, da in einer Wahlregel nicht mehrere System- oder AGI-Befehle ausgeführt werden können. Ein Ausweg wäre die Aufrufe von System-Befehlen in ein AGI-Skript zu verlagern. Kommt noch.

Faxe gehören der Vergangenheit an:  Dennoch hat mir dieses sinnfreie Projekt viel Spaß bereitet. Viel gelernt habe ich bei diesem Projekt zudem auch noch. Einen Faxempfänger unter Asterisk habe ich nur aus Neugierde eingerichtet und um alte Faxgeräte testen zu können. Ich habe ein altes Faxgerät, das noch als Scanner dient, wenn es nicht auf eine hohe Bildqualität ankommt. Damit hat er noch einen praktischen Nutzen. Um eine Kopie zu erzeugen, verschicke ich ein Fax an den Asterisk-Fax-Empfänger und drucke dann die empfangene TIFF-Datei aus.

Weiterführender Link: Hier findet man die Antworten auf fast alle weiteren Fragen rund um das Thema Asterisk.

Auf einem Raspberry Pi lässt sich ein kompletter Telefonserver betreiben, der seinen Teilnehmern über Landesgrenzen hinweg kostenloses Telefonieren von unterwegs oder daheim ermöglicht.
Asterisk-Telefonserver auf einem Raspberry Pi – Installation, Konfiguration, Programmierung, SIP, IAX2, AGI-Skripte, Sicherheit und Tipps zum praktischen Betrieb – 2.11.2022: Diese Seite richtet sich an jene, welche einen Asterisk-Telefon-Server auf einem Raspberry Pi betreiben möchten und später ein kleines Netzwerk aus Asterisk-Servern planen, um ein eigenständiges Telefonnetz aufzubauen. Los geht es mit der Installation von Raspbian und Asterisk auf einem Raspberry Pi und dann nach Lust und Laune immer tiefer in die Programmierung von Asterisk. Die Themen werden laufend erweitert.

Selbstverständlich muss es nicht unbedingt ein Raspberry Pi sein. Andere Linux-Rechner gehen auch. – weiter