Почему Asterisk не сохраняет голосовые сообщения
Если Asterisk не сохраняет голосовые сообщения, проверьте, какой mailbox@context передан в VoiceMail(), существует ли этот ящик и доступен ли фактический каталог хранения. Email отвечает за уведомления, а не за создание записи. Ниже разбираю диагностику на условном примере компании «Зодиак-Трейд».
С чего начать, если Asterisk не сохраняет сообщения
На условном примере компании «Зодиак-Трейд» разберу сценарий: звонок доходит до голосового меню, но сотрудник не находит запись. Это не история о реальном клиенте и не доказательство «типичной причины»: фраза «почта молчит» скрывает несколько разных сбоев. Сначала я устанавливаю, что именно происходит: VoiceMail() не запускается, запись обрывается или сообщение есть, но уведомление не пришло. Эти состояния ведут к разным проверкам. Если нужна помощь с телефонией в составе общей поддержки, я начинаю с аудита IT-инфраструктуры и отдельно фиксирую маршрут звонка.
Слушаю вызов от начала до конца и отмечаю точку отказа. Звонящий слышит приветствие — значит, хотя бы часть диалплана отработала; это ещё не подтверждает, что Asterisk нашёл ящик или создал файл. Если приветствия нет, проверяю ветку вызова и приложение, которому передали звонок. Если приветствие есть, но после сигнала тишина, проверяю запись и аудиопоток. Если запись сохранилась, а письма нет, не трогаю права на каталог наугад: разбираю доставку почты отдельно. Логи полезны именно тогда, когда ищут конкретную операцию и время вызова, а не просто читают весь файл подряд.
В Asterisk контекст диалплана и контекст голосового ящика — разные настройки. Вызов может идти, например, по диалплану office, а приложение должно получить адрес ящика вроде 6001@office, где office — контекст voicemail.conf. Имена могут совпадать, но совпадение не является обязательным: важно, чтобы номер и контекст в аргументе VoiceMail() указывали на определённый ящик. Если контекст не передан, приложение использует контекст по умолчанию; если передан неверный адрес, Asterisk не находит ящик. Подробно про маршруты и контексты я написал в статье об основах диалплана Asterisk.
Для каждого теста я фиксирую внутренний номер, ветку диалплана, переданный mailbox@context и результат: услышал ли звонящий приветствие, появился ли файл и пришло ли уведомление. Один удачный вызов не проверяет все сценарии: маршрут при занятости может отличаться от маршрута при отсутствии ответа. Поэтому проверяю именно ту ветку, на которой проявляется сбой, и повторяю вызов после одной конкретной правки. Время теста нужно не для отчёта ради отчёта: по нему сопоставляются сообщения CLI, журнал Asterisk и очередь почтового транспорта.
- Нет приветствия — проверяйте маршрут и приложение.
- Приветствие есть, файла нет — проверяйте ящик, запись и каталог.
- Файл есть, письма нет — проверяйте почтовую доставку.
Как устроена строка ящика и зачем ей email
Файл voicemail.conf задаёт ящики, а не весь маршрут звонка. Строка ящика состоит из номера, пароля, имени, email, адреса пейджера и дополнительных опций; необязательные поля разделяются запятыми. В образце Asterisk используется форма <mailbox>=<password>,<name>,<email>,<pager_email>,<options>. Если оставить пустое необязательное поле посередине, запятые вокруг него сохраняют позиции следующих значений. Поэтому я проверяю не только вид строки, но и то, в какое поле попал каждый параметр после правки.
Отсутствующий адрес email сам по себе не объясняет, почему не создалась голосовая запись. Email нужен для уведомления о новом сообщении, а вложение записи в письмо включается отдельно. Если адрес не задан, уведомление некуда отправить; если вложение отключено, письмо может прийти без аудиозаписи. Оба случая совместимы с сохранённым сообщением в ящике. Это важное разделение: локальное хранение проверяется по файлу и каталогу, отправка уведомления — по адресу и почтовому каналу. Заглушку вместо адреса я не советую: она маскирует ошибку настройки и не помогает диагностике.
Отправку письма Asterisk передаёт внешней почтовой команде через параметр mailcmd. В официальном образце voicemail.conf показан вариант /usr/sbin/sendmail -t; фактический исполняемый файл и способ отправки зависят от установленной системы. Поэтому проверяю, доступна ли указанная команда процессу Asterisk и принимает ли она сообщение, а затем отдельно смотрю очередь и журнал почтовой службы. Фраза «настройте SMTP в Asterisk» слишком расплывчата: сначала надо понять, какой mailcmd настроен и какой почтовый транспорт за ним стоит. В документации есть и другие опции ящика, но менять их ради проверки записи не нужно.
Проверяя строку, смотрю на секцию контекста и границы полей. Например, если поле pager_email не используется, оно всё равно занимает своё место между email и options; иначе значение опции можно случайно прочитать как адрес пейджера. Для прикрепления аудиозаписи к уведомлению в образце есть опция attach=yes. Она меняет содержимое письма, но не место, куда сохраняется исходное сообщение. После редактирования я отдельно сверяю номер ящика, контекст, адрес получателя и опции. Не копирую строку из чужой установки целиком: в ней могут быть параметры, связанные с другим почтовым транспортом или хранением.
- Сверьте порядок полей и запятые.
- Разделяйте запись сообщения и уведомление.
- Проверьте mailcmd и почтовый транспорт.
Где лежит запись и как проверить доступ
При файловом хранении стандартный spool Asterisk находится в /var/spool/asterisk, а сообщения голосовой почты — в подкаталоге voicemail. Типичный путь включает контекст, номер ящика и папку INBOX: /var/spool/asterisk/voicemail/<context>/<mailbox>/INBOX/. Это ориентир, а не обещание, что на каждом сервере путь будет именно таким: каталоги Asterisk задаются в asterisk.conf, а конфигурация может использовать IMAP или ODBC вместо обычных файлов. Сначала выясняю фактический способ хранения и значение astspooldir, затем ищу сообщение в ожидаемом месте. Если включено IMAP-хранение, Asterisk использует его вместо стандартной файловой структуры; отсутствие файла по стандартному файловому пути тогда не означает, что записи нет. Проверяйте тот backend, который действительно задан конфигурацией, а не ищите сообщение только на диске.
Проверяю права по всей цепочке каталогов от spool до INBOX, владельца процесса Asterisk, доступное место и состояние файловой системы. Важен не абстрактный режим вроде 755, а то, может ли именно запущенный процесс создать файл и каталог в своей фактической конфигурации. Если проверка указывает на отказ доступа, исправляю владельца и разрешения только на нужном участке, по принятой в этой установке схеме. Рекурсивный chown всего дерева voicemail может затронуть чужие данные или не совпасть с тем, как права управляются пакетами и контейнерами. Команда, которая выглядит короткой, не становится от этого безопасной.
Если каталога ящика пока нет, не создаю его вручную первым действием: сначала проверяю, загрузился ли нужный ящик, какой путь использует Asterisk и что написано в журнале во время тестового звонка. Иначе можно создать папку не там, где процесс ищет сообщения. Также исключаю заполнение диска, исчерпание inode и режим только для чтения у точки монтирования. Для локальной файловой системы это отдельные причины отказа записи; при IMAP или ODBC проверяется уже соответствующее хранилище и подключение к нему. Я не меняю права наугад, пока не доказано, что отказ именно в доступе.
Путь и права не объясняют отсутствие звука в уже созданном файле. Если сообщение появляется, но в нём тишина, отдельно проверяю, что слышит Asterisk во время вызова, и аудио в созданном файле. Это уже задача анализа звукового тракта, а не маршрута ящика и права записи в каталог. В проектах я сначала сохраняю исходные логи и делаю один воспроизводимый вызов, чтобы сопоставить время звонка с появлением файла. Такой след быстрее приводит к причине, чем массовая смена владельца каталогов.
На сервере с SELinux обычные права владельца — не единственный слой доступа. Если они выглядят корректно, а журнал показывает отказ, ищу AVC-сообщение в системном аудите: в зависимости от конфигурации оно попадает в /var/log/audit/audit.log, /var/log/messages или журнал systemd. Для поиска недавних отказов Red Hat документирует ausearch -m AVC,USER_AVC -ts recent. Я сопоставляю путь и процесс из записи с тестовым вызовом и исправляю причину в настройке политики или метке. Отключать SELinux ради проверки на рабочей системе — плохой диагностический приём: он скрывает причину и убирает защиту.
- Уточните фактический путь и тип хранилища.
- Проверьте владельца процесса и доступ по всей цепочке.
- Проверьте место, inode и режим монтирования.
Что проверить в диалплане и приложении VoiceMail
VoiceMail() принимает оставляемое сообщение, а VoiceMailMain() даёт владельцу ящика прослушать его и управлять приветствием и PIN. В аргументе VoiceMail() указывают ящик и при необходимости контекст в форме mailbox@context; опции задаются отдельно. Например, u включает приветствие «недоступен», а b — приветствие «занят». Это полезно при разборе ветки вызова: правильный номер без нужного контекста всё равно может привести не к тому ящику. В статье про настройки PJSIP в Asterisk разбираю соседний уровень телефонии, но параметры SIP не заменяют проверку приложения в диалплане.
Смотрю на реальную последовательность при занятости и отсутствии ответа: какой приоритет выполняется после Dial(), какое приложение вызывается и какой адрес ящика ему передают. Не вывожу номер ящика автоматически из имени контекста и не предполагаю, что он равен внутреннему номеру телефона. Для диагностики полезно вручную сверить три значения: условие перехода в voicemail, аргумент VoiceMail() и строку ящика в voicemail.conf. При нескольких контекстах это особенно важно. Сообщение может записываться в один ящик, а сотрудник будет проверять другой — внешне это похоже на потерю записи, хотя файл лежит в другом месте.
Если приложение вызвано с верным ящиком, но файл пустой или не содержит речи, проверяю аудио и тайминг приветствия. Таймауты и параметры обработки вызова принадлежат конкретной конфигурации; менять их по совету «поставьте 15 секунд» без наблюдения за вызовом нельзя. Также я сверяю права на доступ к самому ящику и PIN, особенно если VoiceMailMain() вызывается из доступного многим контекста. Для этого есть отдельные рекомендации по безопасности Asterisk. Старую или новую версию приложения я не назначаю виновником, пока журнал и справка именно установленной сборки этого не показывают.
После выполнения VoiceMail() Asterisk устанавливает переменную канала VMSTATUS со статусом SUCCESS, USEREXIT или FAILED. Я использую её как дополнительную отметку в диалплане и журнале, но не принимаю SUCCESS за доказательство доставки письма: это результат самого приложения, почтовый транспорт проверяется отдельно. Если ветка вызова уходит дальше по диалплану, сопоставляю статус с переходом после приложения и проверяю, не затёр ли его следующий шаг. Такой маркер помогает увидеть, где завершилось приложение; он не заменяет проверку содержимого ящика.
У приложения есть поведение, которое легко принять за обрыв звонка: документация указывает, что если заданный ящик не существует, выполнение диалплана останавливается. Поэтому, если после VoiceMail() ожидается следующий приоритет, я сначала убеждаюсь, что Asterisk нашёл ящик именно в переданном voicemail-контексте. Проверяю конкретный номер и контекст, а не только имя секции. Затем повторяю вызов и сверяю VMSTATUS с журналом. Если ящик существует, а вызов всё равно обрывается, разбираю фактический результат приложения и следующий шаг диалплана; пароль и SMTP здесь ничего не исправят.
- VoiceMail() принимает новое сообщение.
- VoiceMailMain() открывает существующий ящик.
- Сверьте условие перехода, адрес ящика и секцию voicemail.conf.
Порядок проверки без перезапуска всей АТС
Сначала фиксирую версию Asterisk и действующий способ хранения voicemail. Затем сверяю загрузку ящика и контекст в voicemail.conf, маршрут звонка в extensions.conf, права процесса и свободное место. Для списка ящиков можно посмотреть вывод CLI-команды voicemail show users; сам вывод не доказывает, что тестовая запись прошла, поэтому следующим шагом остаётся реальный вызов. Если в журнале есть ошибка чтения конфигурации или открытия файла, сохраняю строку целиком вместе со временем вызова. Без этого легко принять совпадение по времени за причину.
Перед изменением сохраняю копию нужного файла и меняю одну настройку за раз. Для загрузки конфигурации модуля app_voicemail в CLI используется module reload app_voicemail.so; некоторые установки добавляют псевдоним voicemail reload, поэтому я не считаю его универсальной встроенной командой. Полный перезапуск Asterisk не нужен как первый шаг: он прерывает текущие вызовы и не исправит неверный mailbox@context или отсутствие доступа. Если модуль не может перезагрузиться из-за конкретного состояния, это видно в CLI и журнале; тогда выбираю окно работ с учётом текущих звонков.
После правки делаю контрольный звонок, оставляю короткое сообщение, нахожу созданный файл в фактическом хранилище и прослушиваю его. Затем отдельно проверяю уведомление: правильный адрес, параметр вложения, mailcmd и прохождение письма через системный транспорт. Если файла нет — возвращаюсь к маршруту, существованию ящика и доступу к каталогу. Если файл есть и звучит, но письма нет — не меняю диалплан. Такой порядок даёт проверяемый результат: понятно, какой этап заработал и где ещё остаётся сбой. После завершения записываю изменение и результат теста, чтобы следующий администратор не начинал расследование с нуля.
Если я менял конфигурацию, оставляю рядом копию исходного файла, перечень изменённых строк и результат контрольного вызова. При неудаче это позволяет вернуть только затронутую настройку, а не восстанавливать весь Asterisk из резервной копии. Если тестовая запись прошла, но пользователь всё ещё не видит сообщение, проверяю, какой именно контекст и ящик он открывает через VoiceMailMain(), и не использует ли установка другое хранилище. Для почты записываю отдельный результат: очередь приняла письмо, транспорт его отправил, получатель получил сообщение с нужным вложением. Тогда слово «починили» означает подтверждённый сценарий, а не просто успешную перезагрузку модуля.
Если сбой появляется не на каждом звонке, одного успешного сообщения недостаточно. Я сопоставляю несколько контрольных вызовов и отмечаю, меняется ли результат при занятости и отсутствии ответа. Если запись пропадает только на одной линии или в одной ветке, сначала сравниваю соответствующий маршрут и контекст ящика. Глобальные параметры не меняю, пока не воспроизвёл причину. Такой подход помогает отличить постоянную ошибку конфигурации от единичного отказа почтового транспорта или временной проблемы с диском.
- Проверьте загруженный ящик и маршрут вызова.
- Исправляйте одну настройку за раз.
- Подтвердите отдельно файл и email-уведомление.
Частые вопросы
Почему Asterisk не записывает голосовое сообщение?
Проверьте, вызывается ли VoiceMail(), существует ли указанный mailbox@context и может ли процесс Asterisk записать файл в фактическое хранилище. Email проверяйте отдельно: он отвечает за уведомление.
Обязателен ли email в voicemail.conf?
Email нужен для отправки уведомления. Его отсутствие само по себе не означает, что запись голосового сообщения не сохранится.
Какой контекст указывать в VoiceMail()?
Укажите контекст ящика из voicemail.conf в формате mailbox@context. Контекст диалплана и контекст voicemail — отдельные настройки.
Где искать файлы голосовой почты?
При файловом хранении они обычно находятся под astspooldir/voicemail/<context>/<mailbox>/INBOX/. Фактический путь зависит от asterisk.conf и типа хранилища.
Как перезагрузить настройки app_voicemail?
В CLI используйте module reload app_voicemail.so. Псевдоним voicemail reload может быть настроен отдельно; полный перезапуск не нужен для обычной проверки.
Источники
- Asterisk Documentation: Voicemail Overview — Разделяет функции VoiceMail() (оставить сообщение) и VoiceMailMain() (получить сообщения); описывает формат mailbox@context и поведение при пропуске контекста. https://docs.asterisk.org/Configuration/Applications/Voicemail/
- Asterisk Documentation: VoiceMail() — Проверены аргументы приложения, формат mailbox и опции b/u; документация указывает, что выполнение прекращается, если указанный mailbox не существует. https://docs.asterisk.org/Asterisk_24_Documentation/API_Documentation/Dialplan_Applications/VoiceMail/
- Asterisk voicemail.conf.sample — Первичный образец конфигурации Asterisk: формат строки ящика, email-уведомление, опция attach, mailcmd и пример /usr/sbin/sendmail -t; также показывает, что voicemail reload может быть CLI-алиасом module reload app_voicemail.so. https://github.com/asterisk/asterisk/blob/master/configs/samples/voicemail.conf.sample
- Asterisk Documentation: Directory and File Structure — Проверены настраиваемые astetcdir и astspooldir, стандартный /var/spool/asterisk и подкаталог voicemail. https://docs.asterisk.org/Fundamentals/Directory-and-File-Structure/
- Red Hat: Basic SELinux Troubleshooting in CLI — Проверено, где могут регистрироваться AVC-отказы SELinux и как искать недавние записи командой ausearch -m AVC,USER_AVC -ts recent. https://access.redhat.com/articles/2191331
- Asterisk Documentation: IMAP Voicemail Storage — Подтверждено, что при включённом IMAP Asterisk хранит голосовые сообщения в IMAP вместо стандартной файловой структуры. https://docs.asterisk.org/Configuration/Applications/Voicemail/IMAP-Voicemail-Storage/



