Голосовая почта Asterisk: где пропадают записи
АйТи Фреш
Серверы и инфраструктура

Почему Asterisk не сохраняет голосовые сообщения

Автор: , директор ООО «АйТи-Фреш» · · ~15 мин чтения
Телефонная трубка и разошедшиеся лотки как метафора ошибки маршрута голосовой почты Asterisk
Сначала найдите этап, где пропала запись.

Если Asterisk не сохраняет голосовые сообщения, проверьте, какой mailbox@context передан в VoiceMail(), существует ли этот ящик и доступен ли фактический каталог хранения. Email отвечает за уведомления, а не за создание записи. Ниже разбираю диагностику на условном примере компании «Зодиак-Трейд».

С чего начать, если Asterisk не сохраняет сообщения

На условном примере компании «Зодиак-Трейд» разберу сценарий: звонок доходит до голосового меню, но сотрудник не находит запись. Это не история о реальном клиенте и не доказательство «типичной причины»: фраза «почта молчит» скрывает несколько разных сбоев. Сначала я устанавливаю, что именно происходит: VoiceMail() не запускается, запись обрывается или сообщение есть, но уведомление не пришло. Эти состояния ведут к разным проверкам. Если нужна помощь с телефонией в составе общей поддержки, я начинаю с аудита IT-инфраструктуры и отдельно фиксирую маршрут звонка.

Слушаю вызов от начала до конца и отмечаю точку отказа. Звонящий слышит приветствие — значит, хотя бы часть диалплана отработала; это ещё не подтверждает, что Asterisk нашёл ящик или создал файл. Если приветствия нет, проверяю ветку вызова и приложение, которому передали звонок. Если приветствие есть, но после сигнала тишина, проверяю запись и аудиопоток. Если запись сохранилась, а письма нет, не трогаю права на каталог наугад: разбираю доставку почты отдельно. Логи полезны именно тогда, когда ищут конкретную операцию и время вызова, а не просто читают весь файл подряд.

В Asterisk контекст диалплана и контекст голосового ящика — разные настройки. Вызов может идти, например, по диалплану office, а приложение должно получить адрес ящика вроде 6001@office, где office — контекст voicemail.conf. Имена могут совпадать, но совпадение не является обязательным: важно, чтобы номер и контекст в аргументе VoiceMail() указывали на определённый ящик. Если контекст не передан, приложение использует контекст по умолчанию; если передан неверный адрес, Asterisk не находит ящик. Подробно про маршруты и контексты я написал в статье об основах диалплана Asterisk.

Для каждого теста я фиксирую внутренний номер, ветку диалплана, переданный mailbox@context и результат: услышал ли звонящий приветствие, появился ли файл и пришло ли уведомление. Один удачный вызов не проверяет все сценарии: маршрут при занятости может отличаться от маршрута при отсутствии ответа. Поэтому проверяю именно ту ветку, на которой проявляется сбой, и повторяю вызов после одной конкретной правки. Время теста нужно не для отчёта ради отчёта: по нему сопоставляются сообщения CLI, журнал Asterisk и очередь почтового транспорта.

Не путайте контекст extensions.conf с контекстом ящика в voicemail.conf: приложение связывает их через переданный mailbox@context.
Схема вызова VoiceMail и поиска ящика по mailbox@context в 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. Она меняет содержимое письма, но не место, куда сохраняется исходное сообщение. После редактирования я отдельно сверяю номер ящика, контекст, адрес получателя и опции. Не копирую строку из чужой установки целиком: в ней могут быть параметры, связанные с другим почтовым транспортом или хранением.

Нет адреса email — нет email-уведомления; это не доказывает, что запись не сохранилась.
Сравнение записи сообщения Asterisk и отдельной отправки email-уведомления
Запись и уведомление проверяются отдельно.

Где лежит запись и как проверить доступ

При файловом хранении стандартный 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 ради проверки на рабочей системе — плохой диагностический приём: он скрывает причину и убирает защиту.

Не запускайте chown -R и не выставляйте chmod 755 без проверки пользователя службы и реального пути.
Если после проверки адреса ящика, каталога и маршрута причина не нашлась, я могу провести диагностику Asterisk по журналам и контрольному звонку. По результату вы получите список подтверждённых причин и конкретные настройки для исправления. Обсудить задачу

Что проверить в диалплане и приложении 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 здесь ничего не исправят.

Для воспроизводимой проверки используйте точный mailbox@context, а не догадку по имени extension.

Порядок проверки без перезапуска всей АТС

Сначала фиксирую версию 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
Ищите неисправность по результату теста.

Частые вопросы

Почему 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 может быть настроен отдельно; полный перезапуск не нужен для обычной проверки.

Столкнулись с похожей задачей? Обращайтесь — решим

Если у вас происходит что-то из описанного в этой статье — или любая другая проблема с ИТ-инфраструктурой, — обращайтесь в любое время. Мои специалисты и я лично разберём ситуацию, найдём настоящую причину и доведём до решения.

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

📞 +7 903 729-62-41 ✈ Telegram @ITfresh_Boss

С уважением, Семёнов Евгений Сергеевич, директор «АйТи Фреш» — IT-аутсорсинг для компаний до 50 рабочих мест, 15+ лет практики

Источники

© ООО «АйТи-Фреш» · Москва · Все статьи