HylaFAX自社FAXシステム連載
- 第1回:FAX番号を変えずにFAX業務をDXする――HylaFAXとAIで自社サーバーを作った理由
- 第2回:HylaFAXでFAXサーバーを構築する――Debian 13とOMRON ME5614D2の実践記録
- 第3回:HylaFAXがRunning and idleなのに受信できない――T.30 T1 timeoutの原因を追った記録
- 第4回:HylaFAXの受信FAXをWeb管理する――FaxDispatch、PDF化、メール転送の実装
- 第5回:FAX OCRとAIで送信元判別・全文検索――アドレス帳照合でAPI費用を抑える設計
- 第6回:FAXへタブレットで書き込み、そのまま返信――HylaFAX Webシステムの実装
HylaFAXでFAXを受信できるようになっても、受信ファイルはそのままでは社内業務に使いにくい状態です。
HylaFAXは受信原稿をスプール内へ保存しますが、取引先別の整理、既読管理、検索、メール転送、タブレット返信などは別に作る必要があります。
今回は、HylaFAXの受信を起点に、自作Web管理画面へ登録するまでの構成を紹介します。
Webシステムの構成
| 役割 | 使用したもの |
|---|---|
| FAX送受信 | HylaFAX |
| Webサーバー | nginx |
| アプリケーション | PHP 8.4-FPM |
| データベース | MariaDB |
| PDF表示 | PDF.js |
| メール送信 | PHPMailer+外部SMTP |
| 常駐・定期処理 | systemd |
アプリは次の場所へ配置しています。
/srv/tools/fax/
├─ public/ Web公開部分
├─ storage/ FAX原本・変換ファイル
├─ scripts/ 取込・同期・ワーカー
└─ backups/ 配置時バックアップ
FAX原本はWeb公開ディレクトリの外に保存し、PHPを経由して権限確認後に表示します。
受信からWeb表示までの流れ

FAX着信
↓
HylaFAX recvqへTIFF保存
↓
FaxDispatch ─── 失敗時は受信scannerで再検出
↓
受信取込プロセス
├─ Web用storageへ原本をコピー
├─ PDF・ページ画像生成
├─ MariaDBへ登録
├─ メール配送キュー登録
└─ OCR判定キュー登録
↓
Web受信箱へ表示
ここで重要なのは、HylaFAXの受信成功と、Webシステムへの取込成功を分けて記録することです。
通信が成功してTIFFが存在していても、受信後フック、権限、DB接続、PDF変換のどこかで止まれば、Web画面には表示されません。
FaxDispatchを受信の入口にする
HylaFAXでは、受信完了後にFaxDispatchから処理を呼び出せます。
環境やパッケージによって、受信ファイルを示す変数が異なる場合があったため、取込側では$FILENAMEを優先し、存在しない場合は$FILEを使うようにしました。
# 概念例
RECV_FILE="${FILENAME:-$FILE}"
SENDER_INFO="$SENDER"
/srv/tools/fax/scripts/ingest-received-fax.sh \
"$RECV_FILE" \
"$SENDER_INFO"
実際のスクリプトでは、空値、存在しないファイル、重複取込、実行ユーザー、ログ出力を確認してからPHP側へ渡します。
受信TIFFをPDFへ変換する
HylaFAXの受信原稿はTIFFです。
Web上で扱いやすくするため、次の形式を作ります。
- 原本TIFF
- 閲覧・転送用PDF
- ページごとのPNGプレビュー
FAX画像では、横と縦の解像度が同じとは限りません。実際の受信データでは、204×196dpiのような非正方形解像度を扱う必要がありました。
変換時に解像度を無視すると、原稿が縦横に伸びたり、A4比率が崩れたりします。
そのため、TIFFのページサイズと解像度を取得し、原稿の物理寸法を保ったままPDFへ変換します。
重複取込を防ぐ
FaxDispatchが再実行された場合や、受信scannerが再走査した場合に、同じFAXが二重登録されないようにします。
システムでは、HylaFAX側の通信ID、受信ファイル名、取込状態を別テーブルへ記録し、既に登録済みなら処理を止めます。
重複防止をWeb画面の見た目だけで行うのではなく、データベース側で一意性を持たせることが重要です。
受信scannerを用意した理由
受信時フックだけに依存すると、フックの一時的な失敗やサーバー再起動時に取りこぼす可能性があります。
そこで、recvqとデータベースを定期的に照合する受信scannerも動かしています。
- HylaFAXに原本がある
- Webシステムには未登録
- 取込済み記録にも存在しない
この条件を満たすファイルを再度取り込みます。
リアルタイムのFaxDispatchと、定期的な再走査を組み合わせることで、受信原稿が存在するのにWeb画面へ出ない状態を減らしました。
Web受信箱で管理する情報

受信FAXには、次の情報を持たせています。
- 受信日時
- ページ数
- HylaFAX通信ID
- 送信元番号
- REMOTE TSI
- 取引先候補
- OCR状態
- 分類
- 既読・未読
- フォルダ
- 原本とPDFの保存先
Web画面には、受信箱、送信箱、送信待ち、送信済み、送信失敗、ごみ箱、アドレス帳などを用意しました。
FAX機の周囲に紙を積む代わりに、過去の文書を状態付きの業務データとして残します。
メール転送は「通知」と「原本管理」を分ける
受信FAXは、設定した複数のメールアドレスへPDFで転送できます。
ただし、メールを原本保管場所にすると、時間が経ったFAXがメールボックスへ埋もれます。
そのため、役割を分けました。
- Webシステム:原本、検索、履歴、状態管理
- メール:受信通知と外出先での確認
メールを直接送らず、配送キューへ入れる
受信処理の中でSMTP送信まで待つと、メールサーバーが遅い場合に取込全体が止まります。
そこで、受信時はメール配送キューへ登録し、別ワーカーが送信します。
受信取込
↓
mail_delivery_queueへ登録
↓
メールワーカー起動
↓
SMTP送信
↓
成功・失敗を記録
失敗時は、1分、5分、15分、60分、240分というように間隔を広げながら再送します。
一時的なDNS障害やSMTP側の停止で、FAX取込まで失敗扱いになることを避けられます。
メール設定は平文で保存しない
SMTPパスワードなどのメール設定は、Sodiumのsecretboxで暗号化して保存し、サーバー側の鍵ファイルを分離しました。
/etc/fax-tool/mail-secret.key
鍵ファイルはWeb公開領域へ置かず、必要な実行ユーザーだけが読める権限にします。
送信キューとWeb画面を同期する
新規送信や返信をWeb画面から登録すると、最終的にはHylaFAXのsendfaxへ渡します。
sendfax -n -m -d 送信先番号 document.pdf
Webアプリ内で「送信済み」にしただけでは、実際の回線送信と状態がずれます。
そこで、HylaFAXのsendqとdoneqを定期的に読み、Web側の状態を更新します。
- queued:送信待ち
- sending:送信中
- sent:送信完了
- failed:送信失敗
- cancelled:取消
送信に失敗した場合は、HylaFAX側の理由も保存し、再送判断に使います。
最も詰まりやすかったのは権限
FAX通信は成功しているのにWebへ出ない場合、権限が原因になりやすいです。
- HylaFAXが作成したTIFFを取込スクリプトが読めない
- 取込スクリプトが
storageへ書き込めない - PHP-FPMのユーザーがPDFを読めない
- WebアプリがHylaFAXのキューへ接続できない
- ログファイルを別ユーザーが開けない
場当たり的にchmod 777へ逃げると、後でセキュリティ上の問題になります。
各処理を誰が実行するかを整理し、所有者、グループ、ACL、setgidディレクトリなどで必要最小限の権限にします。
スプールを直接Web用ディレクトリにしない
HylaFAXのrecvqはHylaFAXが管理する領域です。Webアプリを動かすために、スプール全体の所有者をwww-dataへ変更したり、chmod 777にしたりする方法は避けます。
安全な考え方は、受信取込専用プロセスだけがrecvqを読み、Webアプリ用の保存領域へコピーすることです。
HylaFAX recvq
↓ 受信取込専用ユーザーだけが読む
/srv/tools/fax/storage/incoming
↓ www-dataは必要な範囲だけ読む
Webアプリ
例えば、専用ユーザーをfax-ingest、共有グループをfaxappとする設計例は次のようになります。
sudo groupadd --system faxapp
sudo usermod -aG faxapp fax-ingest
sudo usermod -aG faxapp www-data
sudo install -d -o fax-ingest -g faxapp -m 2770 /srv/tools/fax/storage/incoming
このコマンドは設計例です。実際には、受信取込サービスの実行ユーザー、PHP-FPMのユーザー、読み取り専用にするか書き込みも許可するかを確認して調整します。HylaFAXのrecvq自体の所有者を、この例に合わせて変更するものではありません。
ログを一か所に寄せすぎない
トラブル時には、次のログを別々に確認します。
- HylaFAX通信ログ
faxgettyのjournal- 受信取込ログ
- PDF変換ログ
- データベースエラー
- メール配送ログ
- Webアプリ監査ログ
すべてを一つの「FAX受信失敗」にまとめると、どの層で止まったか分かりません。
まとめ
HylaFAXでFAXを受信できることと、社内で使えるFAX管理システムが完成することは別です。
実用化するには、受信TIFFの取込、PDF化、プレビュー、重複防止、メール配送、送信キュー同期、権限管理まで必要でした。
ここまで整えることで、FAX機の紙を確認する運用から、Web受信箱を中心とした運用へ移行できます。
次回は、このWebシステムへOCRとAIを組み込み、送信元判別と全文検索をどのように設計したかを紹介します。
シリーズ内の記事
- 第1回:FAX番号を変えずにFAX業務をDXする――HylaFAXとAIで自社サーバーを作った理由
- 第2回:HylaFAXでFAXサーバーを構築する――Debian 13とOMRON ME5614D2の実践記録
- 第3回:HylaFAXがRunning and idleなのに受信できない――T.30 T1 timeoutの原因を追った記録
- 第4回:HylaFAXの受信FAXをWeb管理する――FaxDispatch、PDF化、メール転送の実装
- 第5回:FAX OCRとAIで送信元判別・全文検索――アドレス帳照合でAPI費用を抑える設計
- 第6回:FAXへタブレットで書き込み、そのまま返信――HylaFAX Webシステムの実装


コメント