Интерфейс Exim для фильтрации почты
Перевод выполнен Алексеем Паутовым в рамках некоммерческого проекта RussianLDP (http://www.rldp.ru/). Именно на этом сайте и надлежит искать новые версии, если таковые будут.
54. Интерфейс Exim для фильтрации почты
54.1. Форвардинг и фильтрация в exim
Этот документ описывает пользовательский интерфейс к встроенному средству фильтрации exim и имеет копирайт University of Cambridge 2006. Это относится к exim версии 4.62.
54.1.1. Введение
Большинство почтовых агентов UNIX (программ, которые доставляют почту) дают возможность индивидуальным пользователям задать автоматический форвардинг их почты, обычно путём помещения списка адресов форвардинга в файле с именем .forward в их домашних каталогах. Exim расширяет это средство путём разрешения установки в инструкции форвардинга более, чем просто списка адресов, в смысле предоставления .forward с условиями. Операция установки правил называется фильтрацией (filtering), а файл, который их содержит, называется файлом фильтра (filter file).
Exim поддерживает два различных вида файлов фильтра. Фильтр exim содержит инструкции в формате, который уникален для exim. Фильтр sieve содержит инструкции в формате Sieve, который задан в RFC 3028. Так как это стандартный формат, фильтры sieve уже могут быть знакомы некоторым пользователям. Файлы sieve также могут быть портируемы между различными окружениями. Однако, средство фильтрации exim содержит больше особенностей (типа раскрытия переменных) и лучше интегрируется с окружением хоста (типа использования каналов и внешних процессов).
Выбор, какой вид фильтра использовать, может быть оставлен конечному пользователю, при условии, что системный администратор сконфигурировал exim для обоих видов фильтра. Однако, если важна совместимость, sieve единственный выбор.
Способность использовать фильтрацию или традиционный форвардинг может быть включена системным администратором, и некоторые индвидуальные средства могут быть отдельно включены или отключены. Текущий документ должен предоставить описание, что должно быть включено. В отсутствие этого, проконсультируйтесь у системного администратора. Этот документ описывает, как использовать файл фильтра и формат его содержимого. Он предназначен для использования конечными пользователями. Охватываются оба формата: фильтры sieve и exim. Однако, для фильтров sieve обсуждается лишь то, что воплощено в exim с тех пор, как sieve описан самостоятельно.
Содержимое традиционных файлов .forward тут не описывается. Они обычно содержат лишь список адресов, имён файлов или команд каналов, разделённых запятыми или новыми строками, но также доступны иные типы элементов. Полная детализация может быть найдена в части спецификации exim, посвящённой роутеру redirect, которая также описывает, как системный администратор может установить и контролировать использование фильтрации.
54.1.2. Работа фильтра
Обратите внимание на понимание того, что в exim не происходят доставки при обработке файла фильтра или традиционного файла .forward. Работа фильтра или обработка традиционного файла .forward устанавливает дальнейшие операции доставки, но не проводит их.
Результат обработки фильтра или файла .forward список назначений, к которым будут доставлены сообщения. Сами доставки происходят позднее, вместе со всеми доставками для сообщения. Это означает, что невозможно тестирование успешной доставки при фильтрации. Также, это означает, что любые дубликаты адресов, которые сгенерированы, уничтожаются, поскольку exim никогда не доставляет то же самое сообщение на один и тот же хост более, чем один раз.
54.1.3. Тестирование нового файла фильтра
Файлы фильтра, особенно в сложных случаях, всегда должны быть протестированы для нахождения ошибок. Exim предоставляет средство для предварительного тестирования файла фильтра до его инсталляции. Тестируется синтаксис файла и его базовые операции, а также это может быть использовано с традиционными файлами .forward.
Поскольку фильтр может тестировать содержимое сообщения, требуется тестовое сообщение. Предполагается, что Вы имеете новый файл фильтра, называемый myfilter и тестовое сообщение в файле с именем test-message. Предполагается, что exim инсталлирован с обычным именем /usr/sbin/sendmail (некоторые операционные системы используют /usr/lib/sendmail), может быть использована следующая команда:
/usr/sbin/sendmail -bf myfilter < test-message |
Опция -bf говорит exim, что следующий элемент командной строки задает имя файла фильтра для тестирования. Также есть подобная опция -bF, но используется для тестирования файлов системного фильтра, как противоположность пользовательским файлам фильтра, по этой причине используется только системным администратором.
Тестовое сообщение предоставляется на стандартном вводе. Если в фильтре нет тестов, зависящих от сообщения, может использоваться пустой файл (/dev/null). Предоставляемое сообщение должно начинаться со строк заголовков или разделительной строки сообщения From, которая находится во многих файлах каталогов мультисообщений. Отметьте, что пустые строки завершают строки заголовков. Выдаётся предупреждающее сообщение, если нет прочитанных строк заголовков.
Результат запуска этой команды при условии, что в файле фильтра не было обнаружено ошибок, список действий, которые exim предпринял бы, если бы представленное сообщение было реальным. Например, для фильтра exim вывод:
Deliver message to: gulliver@lilliput.fict.example Save message to: /home/lemuel/mail/archive |
Сами действия при тестировании фильтра этим способом не производятся: тут нет проверок, например, что любые адреса форвардинга действительны. Для фильтра exim если Вы хотите знать причины, почему были предприняты такие действия, добавьте к команде опцию -v. Это заставляет exim выводить результаты любых условных тестов и к отступу вывода в зависимости от глубины вложенности команд if. Дальнейший дополнительный вывод от тестирования фильтра может быть сгенерирован путём команды testprint, как описано ниже.
Когда exim выводит список действий, которые он предпринял бы, если любые текстовые строки включены в вывод, непечатаемые символы конвертируются в их символьные последовательности. В частности, если любая текстовая строка содержит символ новой строки, в тестовом выводе он отображается как \n.
При тестировании фильтра этим способом, exim создаёт конверт (envelope) для сообщения. Получателем по умолчанию будет пользователь, запустивший команду, он же и отправитель, но команда может быть запущена с опцией -f для предоставления иного отправителя. Например:
/usr/sbin/sendmail -bf myfilter \ -f islington@never.where < test-message |
Альтернативно, если не используется опция -f, но первая строка предоставленного сообщения разделитель From, файл каталога сообщений (не то же самое, что и строка заголовка From:), отправитель берётся из неё. Если присутствует -f, содержимое любых строк From игнорируется.
return path то же самое, что и отправитель конверта, если сообщение не содержит заголовка Return-path:, в случае чего он берётся оттуда. Вам не нужно беспокоится об этом, если Вы хотите тестировать возможности файла фильтра, который полагается на адрес отправителя или путь возврата.
Возможно изменить получателя конверта путём задания дальнейших опций. Опция -bfd изменяет домен адреса получателя, тогда как опция -bfl изменяет локальную часть (local part), то есть часть до символа @. Это может использоваться для тестирования некоторых файлов фильтра.
Опции -bfp и -bfs определяют префикс или суффикс локальной части. Они уместны лишь когда осуществляется поддержка для мультиперсональных почтовых ящиков, смотрите описание в секции 3.31 ниже.
54.1.4. Инсталляция файла фильтра
Файл фильтра обычно инсталлируется под именем .forward в Вашем домашнем каталоге, он отличается от обычного файла .forward первой строкой (описано ниже). Однако, имя файла конфигурируемо, и некоторые системные администраторы могут его изменить на какое-то иное имя или местоположение для файлов фильтров.
54.1.5. Тестирование проинсталлированного файла фильтра
Тестирование файла фильтра до инсталляции не может выявить все потенциальные проблемы: например, реально не запускаются команды передачи сообщений в каналы. Некоторые живые тесты следует провести, когда фильтр проинсталлирован.
Если это возможно, протестируйте фильтр путём посылки сообщений от одного из иных аккаунтов. Если Вы посылаете сообщение себе от фильтруемого аккаунта и доставка неудачна, сообщение об ошибке будет послано назад на тот же аккаунт, который может вызвать иную ошибку доставки. Это может вызвать бесконечную последовательность таких сообщений, поскольку сообщение о неудачной доставке самостоятельно генерирует последующие сообщения. Однако обычно ошибка возвращается Вам, а постмастер захочет исследовать приложенное сообщение.
Если Вы хотите тестировать фильтр exim от того же самого аккаунта, разумная предострожность включить строку:
if error_message then finish endif |
54.1.6. Детали фильтрующих команд
Команды фильтрации для фильтров sieve и exim совершенно различаются в синтаксисе и семантике. Механизм sieve определён в RFC 3028, в следующей части я описываю, как он интегрирован в exim. Последующие части детально охватывают фильтрацию exim.
54.2. Файлы фильтра sieve
Код для фильтрации sieve в exim был пожертвован Michael Haardt, и большая часть содержимого этой части взята из примечаний, которые он предоставил. Поскольку sieve расширяемый язык, обратите внимание на понимание Sieve в этом контексте как специфической реализации Sieve для Exim
Эта часть не содержит описание sieve, поскольку оно может быть найдено в RFC 3028, который может быть прочитан вместе с этими примечаниями.
Реализация exim sieve представляет ядро, описанное в RFC 3028, сравнительные тесты, расширения copy, envelope, fileinto и vacation, но не расширение reject. Exim не подерживает уведомления о доставке сообщений (MDNs), таким образом добавление этого к фильтру sieve (как требуется для reject) вызовет недоразумение.
С целью корректной работы sieve в exim системному администратору необходимо создать некоторые настройки в конфигурации exim. Это описано в части роутера redirect в полной спецификации exim.
54.2.1. Распознание фильтров sieve
Файл фильтра интерпретируется как фильтр sieve, если его первая строка
# Sieve filter |
54.2.1. Сохранение в заданные каталоги
Если системный администратор сделал установки как описано в спецификации exim, и Вы используете keep или fileinto для сохранения почты в каталог, абсолютные файлы сохраняются где задано, относительные файлы сохраняются в $home, а inbox находится в стандартном местоположени почтового ящика.
54.2.3. Строки содержащие имена заголовков
RFC 3028 не определяет, что происходит, если строка указывает на поле заголовка, не содержащее допустимое имя заголовка, например, оно содержит двоеточие. Эта реализация генерирует ошибку вместо игнорирования поля заголовка с целью облегчить отладку скриптов, которые вписаны в общую реализацию sieve.
54.2.4. Тест exists с пустыми списками заголовков
Тест exists успешен, лишь если все заданные заголовки существуют. RFC 3028 неясно определяет, что происходит на пустом списке заголовков. Эта реализация вычисляет условие как истинное, интерпретируя RFC в строгом смысле.
54.2.5. Тесты заголовков с неверной кодировкой MIME в заголовке
Некоторые MUA обрабатывают данные неправильно закодированные base64, генерируя чушь. Иные игнорируют хлам после символа равно в данных кодированных base64. RFC 2047 не определяет, как реагировать в этом случае, лишь заявляет, что клиент не должен запрещать обработку сообщения по этой причине. RFC 2045 определяет, что неверные данные должны быть проигнорированы (по видимому, найдя конец строки символов). Также он определяет, что неверные данные могут вызвать отклонение сообщения с ними (и там он указывает на переговоры об истинном нарушении кодирования), что начисто противоречит их игнорированию.
RFC 3028 не определяет, как обрабатывать некорректные слова MIME. Эта реализация обращается с ними буквально, как будто слова корректны, но их набор символов не может быть конвертирован в UTF-8.
54.2.6. Тестирование адреса для нескольких адресов на заголовок
Заголовок может содержать несколько адресов. RFC 3028 неясно определяет, как с ними работать, но затем адреса тестируются проверкой, если что угодно совпадает с чем-то ещё, совпадения одного адреса хватает для удовлетворения условия. Тестирование становится невозможным, если заголовок содержит некоторый набор адресов и не более, но он более логичен, чем позволение неудачи теста, если заголовок содержит дополнительные адреса, кроме того, для которого проводилось тестирование.
54.2.7. Семантика keep
Команда keep эквивалентна:
fileinto "inbox"; |
Она сохраняет сообщение и сбрасывает неявный флаг keep. Она не устанавливает неявный флаг keep: нет команды для установки его как только он был сброшен.
54.2.8. Семантика fileinto
RFC 3028 не определяет, должен ли fileinto пробовать создать почтовый каталог, если он не существует. Эта реализация позволяет системным администраторам конфигурировать использование опций create_directory, create_file и file_must_exist транспорта appendfile. Для дополнительных деталей смотрите транспорт appendfile в спецификации exim.
54.2.9. Семантика redirect
Скрипты sieve предполагаются совместимыми между серверами, таким образом эта реализация не позволяет редирект почты на неквалифицированные адреса, поскольку домен зависит от используемой системы. На системах с виртуальными почтовыми доменами домен по умолчанию, вероятно, не то, что ожидает пользователь.
54.2.10. Строковые аргументы
Могут быть недоразумения, если строка аргументов к require сравнивается регистрозависимо или регистронезависмо. Эта реализация сравнивает их с типом сравнения :is (значение по умолчанию, смотрите раздел 2.7.1 RFC) и компаратором i;ascii-casemap (значение по умолчанию, смотрите раздел 2.7.3 RFC). RFC ясно определяет команду по умолчанию, таким образом, любые отличающиеся реализации грубо нарушают RFC 3028. То же самое каасается имён компатарторов, также заданных как строки.
54.2.11. Множественные единицы
В RFC 3028 есть ошибка: суффикс G означает гига, а не терабайт. Эта ошибка очевидна, поскольку RFC 3028 определяет G как означающее 2^30 (что является гига, а не тера) и это то, что данная реализация использует как фактор масштабирования для суффикса G.
54.2.12. Соответствие RFC
Exim требует, чтобы первая строка фильтра sieve была:
# Sieve filter |
Разумеется, RFC не определяют эту строку. Однако, не ожидайте, что примеры будут работать без её добавления. RFC 3028 требует использования CRLF для завершения строки. Рационально, что CRLF универсально используется в сетевых протоколах для обозначения конца строки. Эта реализация не встраивает sieve в сетевой протокол, а использует скрипты sieve как часть MTA exim.
Поскольку все части exim используют LF как символ новой строки, эта реализация делает точно так же по умолчанию, что может изменить системный администратор (во время компиляции exim) для использования вместо этого CRLF.
Exim нарушает RFC 2822, секцию 3.6.8, путём приёма 8-ми битных имён заголовков, таким образом, эта реализация повторяет это нарушение для сохранения совместимости с exim. Это подготовка к данным в UTF-8.
Скрипты sieve не могут содержать символы NUL в строках, но почтовые заголовки могут содержать символы NUL закодированные MIME, которые никогда не смогут совпасть со скриптами sieve, использующими точное сравнение. По этой причине эта реализация расширяет синтаксис экранированных строк sieve на \0 для описания символа NUL, нарушение \0 создаёт то же самое, что и 0 в RFC 3028. Одинаковые без использования \0 следующие тесты все истинны в этой реализации. Реализации, которые используют строки С-стиля, приводят лишь к оценке первого теста как истинного.
Subject: =?iso-8859-1?q?abc=00def header :contains "Subject" ["abc"] header :contains "Subject" ["def"] header :matches "Subject" ["abc?def"] |
Отметьте, что учитывая, что sieve бывает в MUA, RFC 2074 может быть интерпретировано, что NUL-символы, укорачивающие строку, разрешены для реализаций sieve, однако не рекомендуются. В будущем позволяется использование кодированных символов NUL в заголовках, но это не рекомендуется. Примеры выше показывают как.
RFC 3028 сообщает, что если реализация не в сосотоянии конвертировать набор символов в UTF-8, две строки не могут быть эквивалентны, если одна содержит октеты более, чем 127. Предполагается, что все неизвестные наборы символов однобайтовые наборы символов, с нижними 128 октетами не существующими в US-ASCII, таким образом эта реализация нарушает RFC 3028 и обрабатывает такие слова MIME буквально. Этим способом они иногда могут быть сравнены. Каталог, определённый путём fileinto, не должен содержать последовательность символов .., для избежания проблем с безопасностью. RFC 3028 не определяет синтаксис каталогов, отделяя keep эквивалентом к:
fileinto "INBOX"; |
Эта реализация вместо этого использует inbox. Ошибки скриптов sieve сейчас вызывают тихое помещение сообщений в inbox. RFC 3028 требует, чтобы пользователь был уведомлён об этом условии. Это может быть реализовано в будущем путём добавления строки заголовка к почте, которая была помещена в inbox из-за ошибок в фильтре.
54.3. Файлы фильтра exim
Эта часть содержит полное описание содержимого файлов фильтра exim.
54.3.1. Формат файлов фильтра exim
Отдельно от начального пустого постранства, первый текст в файле фильтра exim должен быть:
# Exim filter |
Это то, что отличает его от обычного файла .forward или файла фильтра sieve. Если у файла нет этой начальной строки (или эквивалентной для фильтра sieve), он обрабатывается как обычный файл .forward, и тот и другой, когда доставляется почта, и когда используется механизм тестирования -bf. Пустое пространство в строке опционально, и может использоваться любой регистр символов. Дальнейший текст в этой строке обрабатывается как комментарий. Например, Вы могли бы иметь:
# Exim filter <<== do not edit or remove this line! |
Оставшаяся часть файла задает последовательность фильтрующих команд, которые состоят из ключевых слов и значений данных. Например, в команде
deliver gulliver@lilliput.fict.example |
54.3.2. Значения данных в командах фильтра
Есть два способа, которыми значения данных могут быть введены:
- Если текст не содержит пустого пространства, они могут быть набраны дословно. Однако, если это часть условия, оно также должно быть свободно от круглых скобок, так как они используются для группирования в условиях.
- Иначе, текст должен быть заключён в двойные кавычки.
В этом случае символ \ (обратный слэш) обрабатывается как экранирующий символ
(escape character) в строке, вызывая специальную обработку
следующего символа или символов:
последовательность значение \n замещается на новую строку \r замещается на возврат каретки \t замещается на табуляцию
Обратный слэш, сопровождаемый тремя восьмеричными цифрами, замещается на символ, определённый этими цифрами, и \x сопровождаемый вплоть до двух шестнадцатеричных цифр обрабатывается подобным образом. Обратный слэш, сопровождаемый иными символами, замещается на второй символ, таким образом, в частности, \" превращается в ", и \\ превращается в \. Элементы данных, помещённые в двойные кавычки, могут быть продолжены на следующей строке путём завершения первой строки обратным слэшом. Любое начальное пустое пространство в начале строки продолжения игнорируется.
В дополнение к символу экранирования, обрабатывающему, что происходит, когда строка помещена в кавычки, много значений данных подчиняются раскрытию строк (string expansion, как описано в следующей секции), в случае чего символы $ и \ также многозначимы. Это способ, если действительно в строке требуется один символ обратного слэша, а строка также помещена в кавычки, должна быть введена последовательность \\\\. Максимальная разрешённая длина строки данных до раскрытия 1024 символа.
54.3.3. Раскрытие строки
Большинство значений данных раскрываются до использования. Раскрытие состоит из замещения подстрок, начинающихся на $, иным текстом. Полные средства раскрытия, доступные в exim, обширны. Если Вы хотите знать всё, что exim может делать со строками, Вы должны проконсультироваться с частью, посвящённой раскрытию строк в документации exim.
В файлах фильтра наиболее частым использованием раскрытия строк является замещение содержимого переменных. Например, подстановка:
$reply_address |
${reply_address} |
Если символ $ реально требуется в раскрываемой строке, он должен быть экранирован обратным слэшом, и, поскольку обратный слэш также экранируется внутри кавычек в вводимых строках, в этом случае он должен быть удвоен. Следующие два примера иллюстрируют два различных пути тестирования на символ $ в сообщении:
if $message_body contains \$ then ... if $message_body contains "\\$" then ... |
Вы можете предотвратить часть строки от раскрытия путём помещения её между двумя \N. Например,
if $message_body contains \N$$$$\N then ... |
54.3.4. Некоторые полезные общие переменные
Полный список переменных доступен в документации exim. Это сокращённый список наиболее полезных в персональном файле фильтра:
- $body_linecount: Число строк в теле сообщения.
- $body_zerocount: Число символов бинарных нулей в теле сообщения.
- $home: В обычных конфигурациях эта переменная содержит пользовательский домашний каталог. Однако, системный администратор может это изменить.
- $local_part: Часть почтового адреса, которая предшествует символу @, обычно логин пользователя. Если включена поддержка мультиперсональных ящиков (смотрите ниже секцию 3.31), а префикс или суффикс локальной части распознан, он удаляется из строки в этой переменной.
- $local_part_prefix: Если включена поддержка мультиперсональных ящиков (смотрите ниже секцию 3.31), а префикс или суффикс локальной части распознан, эта переменная содержит префикс. Иначе, она содержит пустую строку.
- $local_part_suffix: Если включена поддержка мультиперсональных ящиков (смотрите ниже секцию 3.31) и префикс или суффикс локальной части распознан, эта переменная содержит суффикс. Иначе, она содержит пустую строку.
- $message_body: Начальная часть тела сообщения. По умолчанию в эту переменную считывается до 500 символов, но системный администратор может сконфигурировать иное значение. Новые строки в теле конвертируются в единичные пробелы.
- $message_body_end: Финальная часть тела сообщения, отформатированная и ограниченная тем же способом, что и $message_body.
- $message_body_size: Размер тела сообщения в байтах.
- $message_exim_id: Локальная идентификационная строка сообщения, которая уникальна для каждого сообщения, обрабатываемого одним хостом.
- $message_headers: Строки заголовоков сообщения, объединённые в одну строку, с символами новой строки между ними.
- $message_size: Размер всего сообщения в байтах.
- $original_local_part: Когда адрес, который прибывает с сообщением обрабатывается, эта переменная содержит то же самое значение, что и переменная $local_part. Однако, если адрес сгенерирован путём алиасинга, форвардинга или обработки файла фильтра, эта переменная содержит локальную часть оригинального адреса.
- $reply_address: Содержимое заголовка Reply-to:, если сообщение его содержит. Иначе, содержимое заголовка From:. Это адрес, на который обычно посылаются ответы на сообщение.
- $return_path: Путь возврата, это поле отправителя, которое было передано как часть конверта сообщения, если сообщение послано на иной хост. Это адрес, на который отправляются ошибки доставки. Во многих случаях эта переменная имеет то же значение, что и $sender_address, но если, например, раскрывается входящее сообщение на список рассылки, $return_path может быть изменено на адрес ответственного за список рассылки.
- $sender_address: Адрес отправителя, который был принят в конверте сообщения. Это не обязательно содержимое строк заголока From: или Sender:. Для доставки сообщений об ошибке (рикошетов), у них нет адреса отправителя, и эта переменная пуста.
- $tod_full: Полная версия времени и даты, например: Wed, 18 Oct 1995 09:51:40 +0100. Временная зона всегда даётся как числовое смещение от GMT.
- $tod_log: Время и дата в формате, используемом для записи в файлы протоколов exim без временной зоны, например: 1995-10-12 15:32:29.
- $tod_zone: Смещение локальной временной зоны, например: +0100.
54.3.5. Переменные заголовков
Это специальный набор раскрываемых переменных, содержащих строки заголовков при обработке сообщения. Эти переменные имеют имена, начинающиеся с $header_, сопровождаемое именем строки заголовка, завершаемое двоеточием. Например,
$header_from: $header_subject: |
Весь элемент, включая завершающее двоеточие, заменяется содержимым строки заголовка. Если есть более одного заголовка с одним и тем же именем, их содержимое объединяется. Для строк заголовков, чьи данные состоят из списка адресов (например, From: и To:), запятые и символы новой строки вставляются между каждым набором адресов. Для всех других строк заголовоков используется лишь символ новой строки.
Начальное и завершающее пустое пространство удаляется из данных строки заголовка, и если в них есть любые слова MIME, которые закодированы как задано в RFC 2047 (поскольку они содержат не-ASCII символы), они декодируются и переводятся, если возможно, в локальную кодировку. Попытка перевода предпринимается лишь в операционных системах, которые обладают функцией iconv(). Это создаёт такой же поиск по строкам заголовков, как и при показе MUA. Кодировка по умолчанию устанвливается в ISO-8859-1, но это может быть изменено посредством команды headers (смотрите ниже).
Если Вы хотите видеть фактическую кодировку, в которой созданы строки заголовков, можете определить $rheader_ вместо $header_. Этим вставляются немодифицированные строки заголовков.
Также есть промежуточная форма, запрашиваемая путём $bheader_, с удалёнными начальными и конечными пробелами и декодированными словами MIME, но не переведённой кодировкой. Если попытка декодирования того, что на первый взгляд показалось словами MIME, неудачна, возвращается сырая строка. Если декодирование производит бинарные нули, они заменяются знаком вопроса.
Регистр символов следующего за $header_ несущественнен. Поскольку любые печатные символы, исключая двоеточие, могут находится в имени заголовка сообщения (это требование RFC 2822, документ описывает формат почтовых сообщений), в этом случае не должны использоваться фигурные скобки, так как они будут взяты как часть имени заголовка. Два сокращения разрешены в именовании переменных заголовков:
- Начальные $header_, $rheader_ или $bheader_ могут быть заменены $h_, $rh_ или $bh_, соответственно.
- Завершающее двоеточие может быть опущено, если следующий символ является пустым пространством. Символ пустого пространства поддерживается в раскрываемых строках. Однако, это не рекомендуется, поскольку Вы можете забыть двоеточие, когда оно действительно необходимо.
Если сообщение не содержит заголовок с данным именем, подставляется пустая строка. Это важно для корректного правописания имён заголовков. Не используйте $header_Reply_to, когда реально нужен $header_Reply-to.
54.3.6. Пользовательские перемeнные
Есть десять пользовательских переменных с именами $n0 - $n9, число которых может быть увеличено путём команды add (смотрите секцию 3.10). Они могут использоваться для подсчёта очков сообщения, различными способами. Если exim сконфигурирован на работу системного фильтра (system filter) для каждого сообщения, значения в этих переменных копируются в переменные $sn0 - $sn9 в конце системного фильтра, таким образом, делая их доступными в пользовательских фильтрах. Как эти переменные используются, полностью зависит от индивидуальной инсталляции.
54.3.7. Текущий каталог
Содержимое файла фильтра не должно предполагать какой-то рабочий каталог. Лучше всего использовать абсолютные пути для имён файлов: Вы можете использовать переменную $home обычным способом, для ссылки на Ваш домашний каталог. Команда save автоматически вставляет $home в начало всех неабсолютных путей.
54.3.8. Важные доставки
Когда в ходе доставки сообщение обрабатывается файлом фильтра, то, что происходит дальше, то есть после обработки файлом фильтра, зависит от того, установил ли фильтр какие-либо важные доставки (significant deliveries). Если установлена хоть одна важная доставка, фильтр подготовливается к обработке доставки для текущего адреса, и дальнейшая обаботка более не имеет места. Однако, если нет установленных важных доставок, exim продолжает обработку текущего адреса как будто не было файла фильтра, и обычно производит доставку копии сообщения в локальный почтовый ящик. В частности, это происходит в специальном случае, когда файл фильтра содержит лишь комментарии.
Команды доставки deliver, save и pipe по умолчанию важные. Однако, если такой команде предшествует слово unseen, эта доставка не рассматривается как важная. В противоположность, иные команды, типа mail и vacation, не устанавливают важность доставки, если им не предшествует слово seen. Следующие примеры команд устанавливают важные доставки:
deliver jack@beanstalk.example pipe $home/bin/mymailscript seen mail subject "message discarded" seen finish |
Следующие примеры команд не устанавливают важные доставки:
unseen deliver jack@beanstalk.example unseen pipe $home/bin/mymailscript mail subject "message discarded" finish |
54.3.9. Команды фильтра
Команды фильтра, которые описаны в последующих секциях, перeчислены ниже, секция, где они описаны, указана в круглых скобках:
- add увеличивает пользовательскую переменную (секция 3.10).
- deliver доставка на почтовый адрес (секция 3.11).
- fail принудительная ошибка доставки (используется системным администратором) (секция 3.18).
- finish конец обработки (секция 3.16).
- freeze заморозка сообщения (используется системным администратором) (секция 3.19).
- headers установить кодировку заголовков (секция 3.20).
- if условие тестирования (секция 3.21).
- logfile задать файл протоколов (секция 3.15).
- logwrite записать в файл протокола (секция 3.15).
- mail послать ответное сообщение (секция 3.14).
- pipe канал к команде (секция 3.13).
- save сохранить в файл (секция 3.12).
- testprint напечатать при тестировании (секция 3.17).
- vacation заказная форма mail (секция 3.14).
Команда headers имеет дополнительные параметры, которые могут использоваться лишь в системном фильтре. Команды fail и freeze доступны, лишь когда средство фильтрации exim используется как системный фильтр, и поэтому используется лишь системным администратором, а не обычными пользователями.
54.3.10. Команда add
add <number> to <user variable> e.g. add 2 to n3 |
Есть 10 пользовательских переменных этого типа с именами $n0 - $n9. Их значения могут быть получены путём обычного синтаксиса раскрытия (например, $n3) в этих командах. В начале фильтрования все эти переменные содержат ноль. Оба аргумента команды add раскрываются до начала использования, делая возможным добавление переменной к самой себе. Вычитание может приводить к добавлению отрицательных чисел.
54.3.11. Команда deliver
deliver <mail address> e.g. deliver "Dr Livingstone <David@somewhere.africa.example>" |
Эта команда обеспечивает операцию форвардинга. Доставка устаналивается важной, если команде не предшествует unseen (смотрите раздел 3.8). Сообщение шлётся на данный адрес, точно так же, как происходит, если адрес появился в традиционном файле .forward. Если Вы хотите доставить сообщение к нескольким различным адресам, Вы можете использовать несколько, а не одну команду deliver (каждая может иметь лишь один адрес). Однако, от повторяющихся адресов отказываются. Для доставки копии сообщения в Ваш обычный почтовый ящик, Ваш логин должен быть дан как адрес. Один раз адрес обрабатывается механизмом фильтрации, идентичный сгенерированный адрес не будет обработан снова, таким образом не вызывая циклов.
Однако, если Вы обладаете почтовым алиасом, Вы не должны ссылаться на него. Например, если почтовый адрес L.Gulliver приводит к алиасу на lg303, то все ссылки в файле .forward Gulliver должны быть на lg303. Ссылки на алиас не работают для сообщений, которые адресованы на этот алиас, поскольку, как и обработка файл .forward, алиасинг выполняется лишь один раз для адреса, для предотвращения циклов.
Может появляться, опционально, следующий новый адрес, второй адрес, с предшествующим errors_to. Этим изменяется адрес, на который посылаются ошибки доставки форвардившихся сообщений. Вместо отправки сообщения оригинальному отправителю, они идут на новый адрес. Для обычных пользователей разрешено лишь значение пользователя, которому принадлежит обрабатываемый фильтр. Например, пользователь lg303, чей почтовый ящик в домене lilliput.example мог бы иметь файл фильтра, который содержит:
deliver jon@elsewhere.example errors_to lg303@lilliput.example |
Очевидно, использование этой особенности имеет смысл лишь в ситуациях, когда не все сообщения форвардятся. В частности, рикошеты не должны форвадится этим способом, так как вероятны почтовые циклы, если что-то пойдёт не так.
54.3.12. Команда save
save <file name> e.g. save $home/mail/bookfolder |
Эта команда определяет, что копия сообщения будет добавлена к заданному файлу (то есть, файл будет использован как почтовый каталог). Доставка, которая установлена save, важна, если команде не предшествует unseen (смотрите раздел 3.8).
Может быть более одной команды save: каждая вызывает запись копии сообщения в файл, являющийся её аргументом, при условии, что они различны (дублирующиеся команды save игнорируются).
Если имя файла не начинается с символа /, добавляется содержимое переменной $home, если она не пуста. В обычных конфигурациях эта переменная установлена в пользовательском фильтре в пользовательский домашний каталог, но системный администратор может установить её в другой путь. В некоторых конфигурациях $home может быть не задана, в случае чего могут быть сгенерированы неабсолютные пути. Такие конфигурации конвертируют его в абсолютный путь, когда имеет место доставка. В системном фильтре $home никогда не установлена.
Пользователь, разумеется, должен обладать разрешением записывать в файл, и запись файла происходит в процессе работающем от пользователя, под основной группой пользователя. Любые вторичные группы, к которым может принадлежать пользователь, обычно, не используются в аккаунте, однако, системный администратор может сконфигурировать exim для их установки. В дополнение, способность использовать эту команду всеми, контролируется системным администратором: она может быть запрещена на некоторых системах.
Опциональное значение режима может быть задано после имени. Значение режима интерпретируется как восьмеричное число, даже если оно не начинается с нуля. Например:
save /some/folder 640 |
Это даёт возможность пользователям перезадавать общесистемный режим для доставки в файл, который обычно 600. Если существующий файл не имеет корректный режим, он изменяется.
Альтернативная форма доставки может быть включена на Вашей системе, в которой каждое сообщение доставляется в новый файл в заданном каталоге. В этом случае эта функциональность может быть запрошена путём задания после команды save имени каталога, завершаемого слэшем, например:
save separated/messages/ |
Есть несколько различных форматов для таких доставок, проконсультируйтесь с системным администратором или локальной документацией, чтобы узнать, какая (или какие) доступны в Вашей системе. Если эта функциональность не включена, использование пути, завершающегося слэшем, вызывает ошибку.
54.3.13. Команда pipe
pipe <command> e.g. pipe "$home/bin/countmail $sender_address" |
Эта команда определяет, что сообщение будет доставлено к заданной команде, используя канал. Доставка, которую она устанавливает, важна, если команде не предшествует unseen (смотрите раздел 3.8). Помните, однако, что доставки не закончатся, пока обрабатывается фильтр. Все доставки происходят позже. Таким образом, результат работы канала недоступен в фильтре.
Когда доставки завершены, запускается отдельный процесс, и копия сообщения передаётся на стандартный ввод. Процесс работает от пользователя, под первичной группой пользователя. Любые вторичные группы, к которым может принадлежать пользователь обычно не используются в аккаунте, однако, системный администратор может сконфигурировать exim для их установки. Может быть более одной команды pipe: каждая вызывает запись копии сообщения в аргумент pipe при условии, что они различны (дублирующиеся команды pipe игнорируются).
Когда приходит время транспортировки сообщения, команда, предоставленная pipe, разделяется exim на имя команды и несколько аргументов. Они разделяются пустым пространством, исключая аргументы в двойных кавычках, в случае чего обратный слэш интерпретируется как символ экранирования, или в одиночных кавычках, в случае чего экранирование не распознаётся. Отметьте, что вся команда обычно предоставляется в двойных кавычках, второй уровень помещения в кавычки требуется для внутренних двойных кавычек. Например:
pipe "$home/myscript \"size is $message_size\"" |
Раскрытие строки выполняет отдельные компоненты после разделения строки, после чего команда запускается непосредственно exim, она не запускается под оболочкой. Поэтому подстановка не может изменить число аргументов, ни кавычек, обратных слэшей или иных метасимволов shell в переменных, вызывая недоразумение.
Документация для некоторых программ, которые обычно запускаются через этот вид канала, часто советует, что команда должна начинаться с
IFS=" " |
Это команда shell, и она не должна присутствовать в файлах фильтра exim, поскольку ему ненормально запускать команду под shell. Однако, есть опция, которую администратор может установить, вызывая использование shell. В этом случае вся команда раскрывается как одна строка и передаётся shell для интерпретации. Этого рекомендуется избегать всегда, когда возможно, поскольку это может вызвать проблемы, когда вставленные переменные содержат метасимволы shell.
Значение PATH по умолчанию, устанавливаемое для команды, определяется системным администратором, обычно содержит, самое малое, /bin и /usr/bin, таким образом, большинство команд доступны без задания полного пути имени файла. Однако, системный администратор может ограничить средство канала так, что имя команды не сможет содержать любые символы /, и должно быть найдено в одном из каталогов в сконфигурированном PATH. Системный администратор также может вообще заблокировать использование команды pipe.
Когда команда запущена, установлено множество переменных окружения. Полный список для доставок в каналы может быть найден в руководстве exim. Те, которые могут быть полезны для доставок pipe из файлов пользовательских фильтров, таковы:
|
LOCAL_PART, LOGNAME и USER установлены в одно и то же значение, а именно в Ваш логин. LOCAL_PART_PREFIX и LOCAL_PART_SUFFIX могут быть установлены, если exim скнфигурирован распознавать префиксы или суффиксы локальных частей адресов. Например, сообщение, адресованное на pat-suf2@domain.example, может вызвать запуск фильтра для пользователя pat. Если установлена доставка в pipe, LOCAL_PART_SUFFIX будет -suf2, когда работает команда канала. Системный администратор должен специально сконфигурировать exim для доступности этой особенности.
Если Вы запускаете команду, которая является скриптом shell, будьте очень осторожны в использовании данных из входящего сообщения в командах Вашего скрипта. RFC 2822 очень щедр в символах, которым разрешено появляться в почтовых адресах, в частности, адрес может начинаться с вертикальной черты или слэша. По этой причине, Вы всегда должны окружать кавычками любые аргументы, которые связаны с данными сообщения, как тут:
/some/command '$SENDER' |
Запомните, что ранее объяснявшаяся команда канала не запускается во время интерпретации файла фильтра. Фильтр лишь определяет, какие доставки требуются для одного из частных адресов сообщения. Сами доставки происходят позднее, когда exim решит, что всё, что необходимо сообщению, завершено.
Вследствии этого, Вы не можете проверять код возврата из команды канала внутри фильтра. Тем не менее, код возврата команды важен, поскольку exim использует его для принятия решения: была ли доставка удачной или неудачной.
Команда должна возвращать код завершения ноль, если всё прошло успешно. Большинство ненулевых кодов рассматриваются exim как индицирующие ошибку канала. Это рассматривается как неудача доставки, вызывая возврат сообщения отправителю. Однако, есть некоторые коды, которые рассматриваются как временные ошибки. Сообщение остаётся на диске в спуле exim, и доставка пробуется снова, позднее, пока время повторов ошибки доставки не будет слишком долгим. Окончательный код для этого случая может быть задан системным администратором, значения по умолчанию 73 и 75.
Команда канала обычно не должна ничего записывать в свой стандартный вывод или в файловый дескриптор стандартной ошибки. Если это происходит, вне зависмости от записанного, оно обычно возвращается отправителю как ошибка доставки, хотя это действие может быть изменено системным администратором.
54.3.14. Почтовые команды
Есть две команды, которые вызывают создание нового почтового сообщения, каждая из которых считается важной доставкой, если команде не предшествует seen (смотрите раздел 3.8). Это мощное средство, но оно должно использоваться с осторожностью, поскольку есть опасность создания бесконечных последовательностей сообщений. Системный администратор может полностью запретить использование этих команд.
Для помощи в избежении последовательности сообщений, эти команды не имеют силы, когда входящее сообщение является рикошетом (сообщением об ошибке доставки), и сообщения, посылаемые этим способом, обрабатываются как отчёт об ошибке доставки. Таким образом, они не вызывают возврата рикошетов. Базовая команда посыла почты такова:
mail [to <address-list>] [cc <address-list>] [bcc <address-list>] [from <address>] [reply_to <address>] [subject <text>] [extra_headers <text>] [text <text>] [[expand] file <filename>] [return message] [log <log file name>] [once <note file name>] [once_repeat <time interval>] e.g. mail text "Your message about $h_subject: has been received" |
Каждый <address-list> может содержать несколько адресов, разделённых запятыми, в формате строк заголовков To: и Cc:. Фактически, текст, который Вы тут помещаете, копируется в соответствующие строки заголовоков. Он может содержать дополнительную информацию, как почтовый адрес. Например:
mail to "Julius Caesar <jc@rome.example>, \ <ma@rome.example> (Mark A.)" |
Подобным образом текст, предоставленный для from и reply_to, копируется в соответствующие строки заголовков.
Для удобства использования в большинстве случаев также есть команда с именем vacation. Она ведёт себя таким же образом, как и mail за исключением того, что по умолчанию опции subject, file, log, once и once_repeat таковы:
subject "On vacation" expand file .vacation.msg log .vacation.log once .vacation once_repeat 7d |
Предупреждение: Команда vacation всегда должна использоваться условно, подчиняясь наименьшему условию personal (смотрите ниже раздел 3.27) так, чтобы не посылать автоматические ответы на неперсональные сообщения от списков рассылки или ещё каких-то. Отсылка автоматических ответов на списки рассылки или управляющему списком рассылки ошибочна.
Для обеих команд пара аргументов ключ/значение может фигурировать в любом порядке. Должен фигурировать по меньшей мере один из text или file (исключение с vacation, где умолчание file): если представлены обе, текстовая строка фигурирует первой в сообщении. Если expand предшествует file, каждая строка файла подчиняется раскрытию строк до её включения в сообщение.
Несколько строк текста могут быть предоставлены к text путём включения экранирующей последовательности \n в строке, где требуется новая строка. Если команда является выводом в течение тестирования файла фильтра, новые строки в тексте отображаются как \n.
Отметьте, что ключевое слово для создания заголовка Reply-To: reply_to, поскольку ключевые слова exim могут содержать подчёркивания, но не дефисы. Если представлено ключевое слово from, и данный адрес не совпадает с пользователем, владеющим файлом .forward, exim обычно добавляет к сообщению заголовок Sender:, если не сконфигурировано не делать этого.
Ключевое слово extra_headers позволяет добавлять нестандартные строки заголовков к сообщению. Предоставляемые текст должен быть одной или более синтаксически верными строками заголовоков в соответствии с RFC 2822. Вы можете использовать \n внутри текста в кавычках для задания новых строк между заголовками, и продолжающихся строк заголовков. Например:
extra_headers "h1: first\nh2: second\n continued\nh3: third" |
В конце финальной строки заголовков не будет новой строки. Если аргумент to не присутствует, сообщение посылается на адрес в переменной $reply_address (смотрите выше раздел 3.3). Все заголовки In-Reply-To: автоматически включаются в создаваемое сообщение, давая ссылку на идентификатор входящего сообщения.
Если задана return message, входящее сообщение, вызвавшее запуск файла фильтра, добавляется к концу сообщения, и на каждый адрес посылается не более одного сообщения, если не задана once_repeat. Этим определяется временной интервал после которого посылается иная копия сообщения. Интервал задаётся как последовательность чисел, каждое сопровождаемая начальной буквой одного из слов: seconds, minutes, hours, days или weeks. Например,
once_repeat 5d4h |
Обычно имя файла, заданное для once, используется как базовое имя для прямых файловых операций (DBM). Существует несколько различных библиотек DBM. Некоторые операционные системы предоставляют по умолчанию одну, но даже в этом случае при сборке exim могут использоваться иные. С некоторыми библиотеками DBM для определения результата once используются два файла с суффиксами .dir и .pag, добавляемыми к именам. В некоторых других используется один файл с суффиксом .db, или имя используется неизменным.
Использование файла DBM для реализация возможности once означает, что файл растёт до такого размера, как необходимо. Обычно это не проблема, но некоторые администраторы хотят его ограничить. Средство может быть сконфигурировано, чтобы не использовать файл DBM, но вместо этого, используется обычный файл с максимальным размером. Данные в таком файле ищутся последовательно, а если файл запоняется, старые вхождения удаляются для добавления новых. Это средство, которым некоторые корреспонденты могут передавать вторую копию сообщения после непредсказуемого интервала. Проконсультируйтесь с Вашей локальной информацией, чтобы убедиться, что Ваша система сконфигурирована таким способом. Более, чем одна команда mail или vacation может фигурировать в одном запуске файла фильтра: они все не выполняются, когда они все для одного и того же получателя.
54.3.15. Команды протоколирования
Протоколы могут быть взяты при помощи файла фильтра. Это средство обычно доступно в обычных конфигурациях, но есть некоторые ситуации, когда они не могут быть получены. Также, системный администратор может их отключить. Проверьте Вашу локальную информацию, если сомневаетесь.
Протоколирование имеет место, когда файл фильтра интерпретируется. Он не находится в очереди до более позднего времени, как команды доставки. Причина этого в том, что файл протоколов необходимо открывать лишь один раз для каждой операции записи. Есть две команды, ни одна из которых не назначает важную доставку. Первая задаёт файл, в который впоследствии выводится протокол:
logfile <file name> e.g. logfile $home/filter.log |
Имя файла должно быть полностью квалифицированным. Вы можете использовать $home, как в этом примере, для ссылки на Ваш домашний каталог. Имя файла может опционально сопровождаться режимом для этого файла, который используется, если файл создаётся. Например:
logfile $home/filter.log 0644 |
Число интепретируется как восьмеричное, если оно не начинается с нуля. Режим по умолчанию 600. Это предполагает, что команда logfile обычно появляется как первая команда в файле фильтра. Как только появился файл протоколов, для записи в него может быть использована команда logwrite:
logwrite "<some text string>" e.g. logwrite "$tod_log $message_id processed" |
Возможно иметь более, чем одну команду logfile для задания записи в различные файлы протоколов в различных ситуациях. Запись имеет место в конце файла, и символ новой строки добавляется в конце каждой строки, если его там нет. Новая строка может быть помещена в середине строки, используя экранирующую последовательность \n. Строки от одновременных доставок могут чередоваться в файле, так как тут нет взаимной блокировки, таким образом, Вы должны планировать протоколирование с учётом этого. Однако, данные не теряются.
54.3.16. Команда finish
Команда finish, которая не имеет аргументов, вызывает остановку интепретации файла фильтра exim. Она не важное действие, если ей не предшествует seen. Фильтр может содержать лишь одну команду seen finish: это чёрная дыра.
54.3.17. Команда testprint
Иногда полезна возможность распечатать значения переменных, когда тестируется файл фильтра. Команда
testprint <text> e.g. testprint "home=$home reply_address=$reply_address" |
54.3.18. Команда fail
Когда средство фильтрации exim используется как системный фильтр, доступна команда fail для принудительной неудачи доставки. Поскольку эта команда обычно используется лишь системным адмнистратором, и не включена для использования обычными пользователями, она описана в главной спецификации exim более подробно, чем в этом документе.
54.3.19. Команда freeze
Когда средство фильтрации exim используется как системный фильтр, доступна команда freeze для заморозки сообщения в очереди. Поскольку эта команда, обычно, используется лишь системным адмнистратором, и не включена для использования обычными пользователями, она более описана в главной спецификации exim более подробно, чем в этом документе.
54.3.20. Команда headers
Команда headers может использоваться для изменения целевой кодировки, которая используется при переводе содержимого сообщения кодированных строк заголовков, для вставки путём механизма $header_ (смотрите секцию 3.5 выше). Значение по умолчанию может быть установлено в конфигурации exim: если не задано, используется ISO-8859-1. На данный момент поддерживаемый формат headers в файлах пользовательских фильтров, как в этом примере:
headers charset "UTF-8" |
То есть, headers сопровождается словом charset, а затем именем кодировки. Этот частный пример может быть полезным, если Вы хотите сравнить содержимое заголовков со строкой UTF-8. В файлах системного фильтра команда headers может использоваться для добавления или удаления строк заголовков из сообщения. Эти особенности описаны в главной спецификации exim.
54.3.21. Удовлетворение условий команд
Большинство силы фильтрования происходит из способности тестировать условия и удовлетворять условия различных команд, зависящих от результата. Команда if используется для выполнения специальных условий, её общая форма такова:
if <condition> then <commands> elif <condition> then <commands> else <commands> endif |
Тут может быть любое число секций elif и then (включая их отсутствие) и опциональная секция else. Любое число команд, включая вложенные команды if, могут фигурировать в секции <commands>
Условия могут быть скомбинированы, используя слова and и or, а для задания того, как комбинируются отдельные условия, могут использоваться круглые скобки. Без скобок and более приоритетна, чем or. Например:
if $h_subject: contains "Make money" or $h_precedence: is "junk" or ($h_sender: matches ^\\d{8}@ and not personal) or $message_body contains "this is not spam" then seen finish endif |
Условию может предшествовать not для его отрицания, а также есть некоторые отрицательные формы условия, которые более похожи на английский язык.
54.3.22. Условия тестирования строк
Есть несколько условий, которые оперируют текстовыми строками, используя слова begins, ends, is, contains и matches. Если Вы хотите применить тот же самый тест к более, чем одной строке заголовков, можете легко объединить их в одну строку для тестирования, как в этом примере:
if "$h_to:, $h_cc:" contains me@domain.example then ... |
Если имя условия тестирования строки написано в нижнем регистре, тестирование букв происходит без учёта регистра, если оно написано в верхнем регистре (например, CONTAINS), регистр букв берётся в расчёт.
<text1> begins <text2> <text1> does not begin <text2> e.g. $header_from: begins "Friend@" |
Тест begins проверяет присутствие второй строки в начале первой, обе строки будут раскрыты.
<text1> ends <text2> <text1> does not end <text2> e.g. $header_from: ends "public.com.example" |
Тест ends проверяет присутствие второй строки в конце первой, обе строки будут раскрыты.
<text1> is <text2> <text1> is not <text2> e.g. $local_part_suffix is "-foo" |
Тест is проверяет точное соответствие между строками, вначале раскрывая обе.
<text1> contains <text2> <text1> does not contain <text2> e.g. $header_subject: contains "evolution" |
Тест contains проверяет частичное соответствие строк, обе строки будут раскрыты.
<text1> matches <text2> <text1> does not match <text2> e.g. $sender_address matches "(bill|john)@" |
Для теста matches после раскрытия обеих строк вторая интерпретируется как регулярное выражение. Exim использует библиотеку регулярных выражений PCRE, которая предоставляет регулярные выражения, совместимые с perl. Сравнение успешно, если регулярное выражение совпадает с любой частью первой строки. Если Вы хотите, чтобы регулярное выражение совпадало лишь с началом или концом строки, Вы должны явно закодировать требования, используя метасимволы ^ или $. Верхний пример, являющийся неестественным, совпадает со всеми этими адресами:
bill@test.example john@some.example spoonbill@example.com littlejohn@example.com |
Для совпадения лишь с двумя первыми Вы могли бы использовать это:
if $sender_address matches "^(bill|john)@" then ... |
Нужно быть внимательным, если необходим обратный слэш в регулярном выражении, поскольку обратный слэш интерпретируется как экранирующий символ кодом раскрытия строк и обычной обработкой строк в кавычках exim. Например, если Вы хотите проверить адрес отправителя на домен, завершающийся на .com, то регулярное выражение таково:
\.com$ |
Обратный слэш и символ доллара в этом выражении должны быть экранированы при использовании в команде фильтра, так как они будут интерпретированы кодом раскрытия. Таким образом, реально Вы напишете:
if $sender_address matches \\.com\$ |
Альтернативным способом обработки этого является использование флагов раскрытия \N для подавления раскрытия:
if $sender_address matches \N\.com$\N |
Всё, что между двумя вхождениями \N, копируется без раскрытия строки (фактически Вам не нужна финальная последовательность, поскольку она в конце строки). Если регулярное выражения дано в кавычках (обязательно, лишь если оно содержит пустое пространство), Вы должны написать дважды:
if $sender_address matches "\\\\.com\\$" |
if $sender_address matches "\\N\\.com$\\N" |
Если регулярное выражение содержит субвыражение в квадратных скобках, то после успешного сравнения в последующих действиях могут использоваться числовые переменные, типа $1. Если сравнение неудачно, значения числовых переменных остаются неизменными. Предыдущие значения не восстанавливаются после endif. Другими словами, всегда доступен лишь один набор значений. Если условие содержит несколько подусловий, соединённых с помощью and или or, эта строка извлекается из последнего успешного совпадения, которое доступно в последующих действиях. Числовые значения из любых единичных субусловий также доступны для использования в последующих субусловиях, поскольку раскрытие строки условия происходит до его тестирования.
54.3.23. Тестирование числовых условий
Следующие условия доступны для выполнения числовых тестов:
<number1> is above <number2> <number1> is not above <number2> <number1> is below <number2> <number1> is not below <number2> e.g. $message_size is not above 10k |
Аргументы <number> должны раскрываться в строку цифр, опционально сопровождаемую одной из букв K или M (верхнего или нижнего регистра), которые вызывают умножение на 1024 или на 1024x1024, соответственно.
54.3.24. Тестирование важных доставок
Вы можете использовать условие delivered для тестирования, выполняла ли предыдущая команда фильтра установку важной доставки. Например:
if not delivered then save mail/anomalous endif |
Delivered, возможно, плохой выбор имени для этого условия, поскольку сообщение не было реально доставлено ранее, доставка была установлена для последующей обработки.
54.3.25. Тестирование на сообщения об ошибке
Условие error_message истинно, если входящее сообщение является рикошетом (ошибка доставки сообщения). Помещение команды:
if error_message then finish endif |
54.3.26. Тестирование списка адресов
Это средство для циклического обхода списка адресов и применения условия к каждому из них. Оно имеет форму:
foranyaddress <string> (<condition>) |
Круглые скобки, окружающие условие, обязательны для определения границ от возможных последующих субусловий вложенных команд if. Внутри условия переменная раскрытия $thisaddress установлена в некомментирующую часть каждого адреса в строке, по очереди. Например, если строка
B.Simpson <bart@sfld.example>, lisa@sfld.example (his sister) |
if foranyaddress $h_to: ( $thisaddress matches ^\\d{8}@ ) then ... |
Когда истинно общее условие, значение $thisaddress в команде, которая следует за then, берётся последнее значение внутри цикла. В конце команды if значение $thisaddress сбрасывается к тому, каким оно было до этого. Это полезно для избегания использования многочисленных foranyaddress вложенных в одну команду if, если значение $thisaddress используется впоследствии, поскольку оно всегда очищается. Вместо этого следовало бы использовать вложенные команды if.
Строки заголовков могут быть соединены вместе, если проверка применяется более, чем к одному из них. Например:
if foranyaddress $h_to:,$h_cc: .... |
54.3.27. Тестирование на персональность почты
Обычное требование различать входящую персональную почту и почту от почтовых рассылок, от роботов или иных автоматических процессов (например, рикошеты). В частности, это тестирование обычно требуется для vacation messages. Условие personal проверяет, что сообщение не рикошет, и почтовый адрес текущего пользователя присутствует в строке заголовка To:. Также, оно проверяет, что отправитель не текущий пользователь или один из множества обычных демонов, и что в сообщении нет строки заголовка, начинающейся с List-. В конце оно проверяет содержимое строки заголовка Precedence:, если она есть.
Вы должны всегда использовать условие personal, когда генерируете автоматические ответы. Этот пример показывает использование personal в файле фильтра, который отсылает сообщение об отпуске:
if personal then mail to $reply_address subject "I am on holiday" file $home/vacation/message once $home/vacation/once once_repeat 10d endif |
Это заманчиво, когда пишется команда, типа вышеприведённой, для цитирования оригинальной темы в ответе. Например:
subject "Re: $h_subject:" |
Однако, это опасно делать. Это может позволить кому-то иному подписать Вас на выбранный список рассылки, при условии, что список принимает рикошеты как подтверждения о подписке. Из фильтров сообщения всегда шлются как рикошеты. Хорошо управляемые списки требуют, чтобы сообщение не было рикошетом для подтверждения подписки, таким образом, опасность относительно мала.
Если для локальных частей используются префиксы или суффиксы, то есть что-то, что зависит от конфигурации exim (смотрите ниже, раздел 3.31), тесты для текущего пользователя завершаются с полным адресом (включая префикс и суффикс, если они есть), как с удалённым префиксом и суффиксом. Если система сконфигурирована для перезаписи локальных частей почтовых адресов, например, для перезаписи dag46 как Dirk.Gently, перезаписанная форма адресов также используется в тестах.
54.3.28. Адреса алиасов для персональных условий
Вполне обычно для людей, имеющих почтовые аккаунты на нескольких различных системах, форвардить всю их почту на одну систему, и в этом случае проверка на персональную почту должна проверять все их различные почтовые адреса. Для разрешения этого ключевое условие personal может сопровождаться
alias <address> |
if personal alias smith@else.where.example alias jones@other.place.example then ... |
Адреса алиасов обрабатываются как альтернативы пользовательскому почтовому ящику при тестировании содержимого строк заголовков.
54.3.29. Детали персональных условий
Основной тест personal примерно эквавалентен следующему:
not error_message and $message_headers does not contain "\nList-Id:" and $message_headers does not contain "\nList-Help:" and $message_headers does not contain "\nList-Subscribe:" and $message_headers does not contain "\nList-Unsubscribe:" and $message_headers does not contain "\nList-Post:" and $message_headers does not contain "\nList-Owner:" and $message_headers does not contain "\nList-Archive:" and ( "${if def h_auto-submitted:{present}{absent}}" is "absent" or $header_auto-submitted: is "no" ) and $header_precedence: does not contain "bulk" and $header_precedence: does not contain "list" and $header_precedence: does not contain "junk" and foranyaddress $header_to: ( $thisaddress contains "$local_part $domain" ) and not foranyaddress $header_from: ( $thisaddress contains "$local_part@$domain" or $thisaddress contains "server@" or $thisaddress contains "daemon@" or $thisaddress contains "root@" or $thisaddress contains "listserv@" or $thisaddress contains "majordomo@" or $thisaddress contains "-request@" or $thisaddress matches "^owner-[^@]+@" ) |
Переменная $local_part содержит локальную часть почтового адреса пользователя, файл фильтра которого работает, обычно это Ваш логин. Переменная $domain содержит почтовый домен. Как объяснено выше, если заданы алиасы или перезапись, или если используются префиксы и суффиксы, тесты для текущего пользователя завершаются с альтернативными адресами.
54.3.30. Тестирование статуса доставки
Есть два условия, которые предназначены, главным образом, для использования в файлах системного фильтра, но которые также доступны в файлах пользовательских фильтров. Условие first_delivery истинно, если это первый процесс, пытающийся доставить сообщение и ложно в других случаях. Этот индикатор не сбрасывается после успешного завершения первого процесса доставки: если происходит сбой, или неполадки с питанием (например), следующая доставка предпринимается так же, как первая (first delivery).
В пользовательском файле фильтра first_delivery будет ложно, если до этого в фильтре были ошибки, или доставка для пользователя неудачна, например, из-за ошибки квоты, или если форвардинг к удалённому адресу был задержан по каким-то причинам.
Условие manually_thawed истинно, если сообщение было заморожено по каким-то причинам, а впоследствии разморожено системным администратором. Оно необычно для применения в пользовательских файлах фильтров.
54.3.31. Пользовательские мультипочтовые ящики
Системный администратор может сконфигурировать exim так, что пользователи могут установить варианты их почтовых адресов и обрабатывать их раздельно. Проконсультируйтесь с системным администратором или локальной документацией, чтобы узнать, включено ли это средство в Вашей системе, а если да, каковы его детали.
Средство включает в себя использование префикса или суффикса в почтовом адресе. Например, вся почта, адресованная на lg303-<something>, была бы собственностью пользователя lg303, который мог бы определить, как она должна быть обработана, в зависмости от значения <something>.
Возможны два способа, которыми это можно сделать. Первая возможность: использование нескольких файлов .forward, которые должны быть файлами фильтра, таким образом, они могут различать разные случаи, путём ссылки на переменные $local_part_prefix или $local_part_suffix, как в последнем примере в секции 3.33, ниже.
Возможно сконфигурировать exim на поддержку обоих схем одновременно. В этом случае, специфический файл .forward-foo ищется первым, если он не найден, используется основной файл .forward.
Тест personal (смотрите раздел 3.27) включает префиксы и суффиксы в свои проверки.
54.3.32. Игнорирование ошибок доставки
Как было объяснено выше, фильтрация лишь устанавливает адреса для доставки, но доставки реально не происходят, пока активен файл фильтра. Если любой сгенерированный адрес впоследствии переносит ошибку доставки, сообщение об ошибке генерируется обычным способом. Однако, если команда фильтра, которая устанавливает доставку, предваряется словом noerror, ошибки для этой доставки и любых доставок в результате неё (то есть, из алиасинга, форвардинга или вызванных файлом фильтра) игнорируются.
54.3.33. Примеры команд фильтра exim
Простой форвардинг:
# Exim filter deliver baggins@rivendell.middle-earth.example |
Обработка отпуска, используя традиционные средства, предполагая, что .vacation.msg и иные файлы находятся в Вашем домашнем каталоге:
# Exim filter unseen pipe "/usr/ucb/vacation \"$local_part\"" |
Обработка отпуска внутри exim: вначале должен быть создан файл с именем .vacation.msg в Вашем домашнем каталоге:
# Exim filter if personal then vacation endif |
Файлы некоторых сообщений по теме:
# Exim filter if $header_subject: contains "empire" or $header_subject: contains "foundation" then save $home/mail/f+e endif |
Сохранение всех несрочных сообщений по будним дням:
# Exim filter if $header_subject: does not contain "urgent" and $tod_full matches "^(...)," then save $home/mail/$1 endif |
Отбрасывание прочь всех сообщений от одного сайта, исключая письма от postmaster:
# Exim filter if $reply_address contains "@spam.site.example" and $reply_address does not contain "postmaster@" then seen finish endif |
Обработка персональных мультипочтовых ящиков:
# Exim filter if $local_part_suffix is "-foo" then save $home/mail/foo elif $local_part_suffix is "-bar" then save $home/mail/bar endif |