Гид по технологиям

Направление входящей почты Exim в ваш скрипт

7 min read Почта Обновлено 01 Dec 2025
Exim: направить входящую почту в скрипт
Exim: направить входящую почту в скрипт

Иллюстрация: значки электронной почты, исходящие от источника света

Быстрые ссылки

  • Управление конфигурацией Exim

  • Создание маршрутизатора

  • Создание транспорта

  • Использование переменных окружения

  • Коды возврата

  • Вызов команды

  • Заключение

Введение

Exim — распространённый MTA (агент передачи почты) для Unix-подобных систем. Он гибок и позволяет настраивать маршруты и способы доставки. В этой статье показано, как перенаправить входящие сообщения в ваш собственный скрипт для дальнейшей обработки.

Предположим, что Exim уже установлен и принимает почту. Если вы начинаете с нуля, официальная вики Exim даёт подробные инструкции по установке.

Управление конфигурацией Exim

Подход к хранению конфигурации зависит от дистрибутива и способа установки. Exim, собранный из исходников, обычно использует файл

src/configure.default

в качестве конфигурации по умолчанию.

Для установки через пакетный менеджер конфигурационный файл чаще всего находится по одному из путей:

/etc/exim/config

или

/etc/exim.conf

Чтобы узнать точный путь, используйте:

exim -bP configure_file

Debian-подобные системы имеют особенности: конфигурация может быть в одном файле

/etc/exim4/exim4.conf.template

или разбита на части в каталоге

/etc/exim4/conf.d

После изменений в split-конфигурации нужно выполнять

update-exim4.conf

для сборки единого файла, который реально читает Exim. После правок перезапустите Exim:

service exim4 restart

Важно: изменения в конфигурации не применяются без перезапуска/перезаписи файла, который читает Exim.

Создание маршрутизатора

Чтобы направить почту в приложение, сначала определите собственный router. Маршрутизаторы сопоставляют входящие сообщения условиям и выбирают, каким транспортом доставлять сообщение.

Маршрутизаторы обрабатываются в порядке их появления в конфигурационном файле. Любой router до вашего может перехватить сообщение раньше, поэтому поместите ваш router в правильное место (обычно в секцию ROUTERS CONFIGURATION).

Если вы используете split-конфигурацию в Debian, создайте файл в:

/etc/exim4/conf.d/routers

Файлы объединяются в алфавитном порядке, поэтому выбирайте имя файла соответствующим образом (например, 40_custom_router).

Пример простого router:

example_router:

driver = accept

domains = example.com

transport = example_transport

Этот router принимает любые письма для домена example.com и передаёт их на транспорт example_transport.

Совет по отладки: временно добавляйте в лог log_message или включайте более подробный уровень логирования, чтобы увидеть, сработал ли ваш router.

Создание транспорта

После принятия сообщения router’ом его доставляет transport. Транспорты реализуют процесс фактической доставки: через SMTP, локальному пользователю, в файл или в pipe для вызова программы.

Порядок объявлений transport’ов не важен: router указывает конкретный transport, который будет использоваться.

Добавьте транспорт в секцию TRANSPORTS CONFIGURATION или в /etc/exim4/conf.d/transports на Debian.

Пример транспорта, вызывающего PHP-скрипт:

example_transport:

driver = pipe

command = /usr/bin/php /var/www/html/handle_incoming_email.php

user = www-data

group = www-data

В этом случае Exim запускает указанный command и передаёт письмо в формате RFC на stdin команды. Команда исполняется от имени пользователя www-data.

Пример получения письма в PHP (чтение из stdin):

// Получение содержимого письма из стандартного ввода в PHP
$email = fopen("php://stdin", "r");

// To: user@example.com
// Subject: Demo Email
//
// This is an email.

Проверьте корректность прав доступа к сценариям и окружению пользователя, под которым выполняется команда.

Важно: если ваш скрипт требует определённой оболочки или сложной последовательности команд, используйте use_shell в транспорте (см. раздел “Вызов команды”).

Переменные окружения

Exim задаёт ряд переменных окружения перед вызовом команды. Это удобно для получения метаданных без парсинга полного письма.

Типичные переменные:

  • DOMAIN — домен, на который принято письмо.
  • MESSAGE_ID — внутренний идентификатор Exim для сообщения.
  • RECIPIENT — адрес получателя.
  • SENDER — адрес отправителя.

Вы можете добавить собственные переменные через опцию environment в конфигурации транспорта. Формат — список пар ключ=значение через запятую:

example_transport:

environment = foo=bar,demo=example

Примечание: значения не интерполируются оболочкой, если вы не используете use_shell.

Коды возврата и поведение Exim

Команда должна завершаться с кодом 0 для подтверждения успешной доставки. Любой ненулевой код считается ошибкой — отправителю придёт bounce.

Если вы хотите игнорировать код возврата, установите ignore_status в транспорте.

Опция temp_errors позволяет указать список кодов выхода, которые считаются временной ошибкой; тогда Exim отложит доставку и попробует снова позже.

return_fail_output = true добавит stdout вашего скрипта в текст bounce-сообщения — это можно использовать для передачи подробного объяснения отправителю.

Примеры настроек:

example_transport:

ignore_status

# или указать временные ошибки

temp_errors = 75,76

# включить возврат stdout в bounce

return_fail_output = true

Важно: не включайте черезмерно подробные сообщения в bounce для публичных почтовых систем — это может раскрыть внутреннюю информацию.

Вызов команды и таймауты

По умолчанию Exim вызывает команду напрямую. Если в транспорте установить use_shell, команда будет передана /bin/sh.

По умолчанию время выполнения команды ограничено одной часовой сессией (1 час). Таймаут считается ошибкой: команда будет убита и отправителю вернётся bounce. Значение таймаута можно изменить с помощью timeout. Если добавить timeout_defer, таймаут будет считаться временной ошибкой.

Пример:

example_transport:

timeout = 5m

timeout_defer

Конкурентность: один и тот же скрипт может запускаться параллельно при одновременном приходе нескольких писем. Не используйте глобальные блокировки, которые запрещают параллельное выполнение; лучше проектировать обработчик так, чтобы он корректно работал в параллельных инстанциях, либо используйте внешнюю систему очередей.

Логирование и отладка

  • Включайте логирование ошибок в самом скрипте (файлы, syslog, stderr).
  • Временный режим: перенаправьте почту в локальный файл для тестов вместо вызова скрипта (driver = appendfile) или используйте тестовый router с ограниченным IP/доменом.
  • Увеличьте уровень логов Exim для диагностики (exim -d или через конфиг).
  • Тестируйте вызов команды вручную под тем же пользователем и окружением, что и Exim.

Важно: многие проблемы связаны с окружением (PATH, доступ к PHP-бинарю, права на файлы). Симулируйте окружение Exim при ручном тесте: sudo -u www-data /usr/bin/php /var/www/html/handle_incoming_email.php < sample.eml.

Тестовые случаи и приёмка

Критерии приёмки

  • Сообщение, отправленное на адрес в домене, обрабатывается и приводит к коду выхода 0.
  • Скрипт корректно получает исходное письмо на stdin в формате RFC и сохраняет/обрабатывает требуемые заголовки и тело.
  • В случае ошибки скрипт возвращает код и Exim либо отдаёт bounce, либо откладывает доставку согласно настройкам.
  • Логирование содержит достаточные сведения для диагностики причины отказа.

Примеры тест-кейсов

  1. Простое письмо с телом и заголовками. Ожидаем: код 0 и запись в базу/файл.
  2. Большое письмо (>10 МБ) — проверить поведение, таймауты и память.
  3. Одновременное прибытие 10 писем — проверить параллельное выполнение и корректность обработки.
  4. Скрипт возвращает ненулевой код, включено temp_errors — сообщение откладывается.
  5. Скрипт пишет в stdout подробности и return_fail_output = true — отправитель получает понятный bounce.

Рекомендации по безопасности и надёжности

  • Минимизируйте права пользователя, от которого запускается скрипт (least privilege).
  • Проверяйте и валидируйте внешний ввод (заголовки, вложения).
  • Ограничьте размер принимаемых сообщений и завершающие таймауты.
  • Разделяйте обработку: быстрый фильтр в Exim + асинхронная очередь для тяжёлой обработки.

Примечание: передавать управляющие данные в stdout для включения в bounce стоит осторожно, чтобы не раскрывать чувствительной информации.

Модель принятия решений (мини-методология)

  1. Определите цель: что должно сделать приложение с письмом (лог, автоответ, запись в БД, преобразование).
  2. Спроектируйте контракт: какой вход (RFC-формат на stdin), какие переменные окружения нужны, ожидаемые коды возврата.
  3. Настройте router, укажите transport = pipe с нужными опциями.
  4. Реализуйте и локально протестируйте скрипт под тем же пользователем и окружением.
  5. Деплойте изменения в отдельной тестовой зоне, наблюдайте логи и корректируйте таймауты/переменные.

Роль-ориентированные чек-листы

Для администратора:

  • Проверить путь конфигурации Exim: exim -bP configure_file.
  • Разместить router в правильной секции/файле.
  • Перезапустить Exim и проверить логи на ошибки.

Для разработчика приложения:

  • Обеспечить приём письма из stdin в формате RFC.
  • Логировать ошибки и возвращать понятные коды выхода.
  • Тестировать под пользователем, от которого запускает Exim.

Для тестировщика:

  • Подготовить набор .eml файлов с разными кейсами.
  • Проверить поведение при ошибках/таймаутах.
  • Убедиться, что bounce-сообщения информативны при необходимости.

Галерея крайних случаев (Edge-case gallery)

  • Письмо с повреждёнными заголовками: как ведёт себя парсер.
  • Вложение с вирусом: интеграция с антивирусом на этапе обработки.
  • Почта с множеством получателей: маршрутизация на несколько вызовов/параллельная обработка.
  • DNS-сбоии/серверы бумеранг: внешние задержки при обратной проверке.
  • Большие потоки спама: защита от DDoS/ограничение количества одновременно запущенных процессов.

Примеры альтернативных подходов

  • Вместо pipe писать в очередь (RabbitMQ, Redis) и обрабатывать письма асинхронно отдельными воркерами.
  • Использовать LMTP/SMTP локальный агент, который принимает и сразу пересылает сообщения на приложение.
  • Доставлять в файл (appendfile), а затем периодически считывать файлы и обрабатывать их.

Когда pipe — плохой выбор: если обработка занимает длительное время или требует тяжёлых ресурсов. В таких случаях предпочтительнее асинхронная очередь.

Краткое резюме

Exim позволяет гибко направлять входящие сообщения в ваши приложения через router + transport с драйвером pipe. Обратите внимание на переменные окружения, коды возврата, таймауты и права пользователей. Тщательно протестируйте сценарии ошибок и параллельную обработку.

Важное: проектируйте обработчик так, чтобы он был отказоустойчивым, безопасным и предсказуемым при высоких нагрузках.


Фактбокс

  • По умолчанию таймаут выполнения команды в Exim — 1 час.
  • Команда получает полностью RFC-совместный текст письма на stdin.
  • Переменные окружения (DOMAIN, RECIPIENT, SENDER, MESSAGE_ID) доступны до выполнения команды.

Глоссарий: MTA — Mail Transfer Agent (агент передачи почты); router — модуль маршрутизации внутри Exim; transport — модуль доставки сообщения.

Список литературы и дальше читать

  • Официальная документация Exim (wiki и справочник параметров).
Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Как сменить MAC-адрес в Windows и Ubuntu
Сеть

Как сменить MAC-адрес в Windows и Ubuntu

Incogni: защита личных данных от дата‑брокеров
Конфиденциальность

Incogni: защита личных данных от дата‑брокеров

Как смотреть фильмы Marvel на Disney+ — порядок выхода
Развлечения

Как смотреть фильмы Marvel на Disney+ — порядок выхода

Автоматическое пробуждение ПК в Windows 10
Windows

Автоматическое пробуждение ПК в Windows 10

Резервное копирование WhatsApp в Google Drive
Мобильные советы

Резервное копирование WhatsApp в Google Drive

Как быстро переключаться между вкладками в Windows
Windows

Как быстро переключаться между вкладками в Windows