Skip to main content

Chapter 19: Voicemail

The mod_voicemail module provides integrated voicemail for FreeSWITCH, supporting per-user mailboxes defined in the user directory, caller-side recording, subscriber-side playback and configuration menus, and email delivery of messages with optional audio attachments.

Getting Started

Prerequisites: mod_voicemail must be loaded. Confirm it appears in autoload_configs/modules.conf.xml. The module reads its configuration from autoload_configs/voicemail.conf.xml.

Minimum working configuration steps:

  1. Confirm voicemail.conf.xml contains a profile named default (the vanilla configuration ships one).
  2. Ensure each user in the directory has a vm-password param set (see Section 19.3).
  3. Confirm the dialplan extensions 4000 and *98 (or their equivalents) exist to route mailbox check calls (see Section 19.6).
  4. For email delivery, configure a working MTA on the FreeSWITCH host and set email-from inside the profile's <email> block.

A caller who reaches a busy or unanswered extension is bridged to:

<action application="bridge" data="loopback/app=voicemail:default ${domain_name} ${dialed_extension}"/>

This invokes the voicemail application in leave-message mode for the mailbox matching ${dialed_extension} in the default profile.


Profile Configuration

Profiles are defined in autoload_configs/voicemail.conf.xml. Each profile is a named collection of parameters that governs recording behavior, DTMF menus, storage paths, and email delivery. Multiple profiles can coexist; each invocation of the voicemail dialplan application specifies which profile to use.

<configuration name="voicemail.conf" description="Voicemail">
<settings>
</settings>
<profiles>
<profile name="default">
<param name="file-extension" value="wav"/>
<param name="terminator-key" value="#"/>
<param name="max-login-attempts" value="3"/>
<param name="digit-timeout" value="10000"/>
<param name="min-record-len" value="3"/>
<param name="max-record-len" value="300"/>
<param name="max-retries" value="3"/>
<param name="tone-spec" value="%(1000, 0, 640)"/>
<param name="callback-dialplan" value="XML"/>
<param name="callback-context" value="default"/>
<param name="play-new-messages-key" value="1"/>
<param name="play-saved-messages-key" value="2"/>
<param name="login-keys" value="0"/>
<param name="main-menu-key" value="0"/>
<param name="config-menu-key" value="5"/>
<param name="record-greeting-key" value="1"/>
<param name="choose-greeting-key" value="2"/>
<param name="change-pass-key" value="6"/>
<param name="record-name-key" value="3"/>
<param name="record-file-key" value="3"/>
<param name="listen-file-key" value="1"/>
<param name="save-file-key" value="2"/>
<param name="delete-file-key" value="7"/>
<param name="undelete-file-key" value="8"/>
<param name="email-key" value="4"/>
<param name="pause-key" value="0"/>
<param name="restart-key" value="1"/>
<param name="ff-key" value="6"/>
<param name="rew-key" value="4"/>
<param name="skip-greet-key" value="#"/>
<param name="previous-message-key" value="1"/>
<param name="next-message-key" value="3"/>
<param name="skip-info-key" value="*"/>
<param name="repeat-message-key" value="0"/>
<param name="record-silence-threshold" value="200"/>
<param name="record-silence-hits" value="2"/>
<param name="web-template-file" value="web-vm.tpl"/>
<param name="db-password-override" value="false"/>
<param name="allow-empty-password-auth" value="true"/>
<param name="operator-extension" value="operator XML default"/>
<param name="operator-key" value="9"/>
<param name="vmain-extension" value="vmain XML default"/>
<param name="vmain-key" value="*"/>
<email>
<param name="template-file" value="voicemail.tpl"/>
<param name="notify-template-file" value="notify-voicemail.tpl"/>
<param name="date-fmt" value="%A, %B %d %Y, %I %M %p"/>
<param name="email-from" value="${voicemail_account}@${voicemail_domain}"/>
</email>
<!--<param name="storage-dir" value="$${storage_dir}"/>-->
<!--<param name="odbc-dsn" value="dsn:user:pass"/>-->
</profile>
</profiles>
</configuration>

Profile Parameter Reference

Recording and audio format:

ParameterPurposeAccepted ValuesDefault
file-extensionAudio format for recorded messages and greetingsAny format string supported by the installed codec modules, e.g. wav, mp3wav
terminator-keyDTMF digit that ends a recordingSingle DTMF digit#
min-record-lenMinimum recording duration in seconds; recordings shorter than this are discardedInteger >= 03
max-record-lenMaximum message recording duration in secondsInteger >= 0300
tone-specTGML tone specification played as the record-beep before message recordingTGML string%(1000, 0, 640)
record-silence-thresholdEnergy threshold below which audio is considered silence during recordingInteger (0-10000)200
record-silence-hitsNumber of consecutive silence frames required to stop recordingInteger2
record-sample-rateOverride the sample rate of recorded files; useful for players with limited codec support (e.g. 11025 for some email clients)Integer (Hz); 0 means use channel native rate0 (native)
record-titleID3-style title tag embedded in recorded filesStringFreeSWITCH Voicemail
record-commentID3-style comment tag embedded in recorded filesStringFreeSWITCH Voicemail
record-copyrightID3-style copyright tag embedded in recorded filesStringhttp://www.freeswitch.org
convert-cmdShell command used to convert recorded files to another format before email attachment; used together with convert-extCommand string(none)
convert-extFile extension produced by convert-cmd; the converted file is used as the email attachmentExtension string(none)
auto-playback-recordingsWhen true, newly recorded greetings or name recordings are played back immediately after recordingtrue, falsefalse

Session and menu behavior:

ParameterPurposeAccepted ValuesDefault
digit-timeoutMilliseconds to wait for a DTMF digit during menu navigationInteger (ms)10000
max-login-attemptsNumber of failed PIN attempts allowed before the mailbox check session is terminatedInteger3
max-retriesMaximum number of retries for menu input before the session endsInteger3
play-new-messages-lifoWhen true, new messages are played in last-in-first-out order (newest first)true, falsefalse
play-saved-messages-lifoWhen true, saved messages are played in last-in-first-out order (newest first)true, falsefalse
play-date-announcementControls when the message date/time stamp is announced during playbackfirst, last, neverfirst
db-password-overrideWhen true, the password stored in the voicemail database takes precedence over the directory vm-password paramtrue, falsefalse
allow-empty-password-authWhen true, a user with no password set can authenticate with no inputtrue, falsetrue

Callback and transfer destinations:

ParameterPurposeAccepted ValuesDefault
callback-dialplanDialplan type used when a subscriber presses the callback key during message playbackXML, ENUM, or other configured dialplan typeXML
callback-contextDialplan context used for the callback callContext name stringdefault
operator-extensionDestination transferred to when the caller presses the operator key; format is dest [dialplan] [context]Destination string(empty; operator key disabled)
operator-keyDTMF digit that transfers the caller to operator-extension during greeting playbackSingle DTMF digit(empty)
vmain-extensionDestination transferred to when the subscriber presses the vmain key; format is dest [dialplan] [context]Destination string(empty)
vmain-keyDTMF digit that jumps to vmain-extension during mailbox checkSingle DTMF digit(empty)

Storage and database:

ParameterPurposeAccepted ValuesDefault
storage-dirBase directory for storing voicemail message files; when empty, messages are stored under the global FreeSWITCH storage directoryAbsolute path(empty; uses global storage dir)
storage-dir-sharedWhen true, mailbox directories under storage-dir include a voicemail/ segment in the path, enabling a shared storage root across domainstrue, falsefalse
odbc-dsnODBC data source name for storing voicemail metadata in an external database; format dsn:user:passDSN string(none; uses SQLite)
dbnameOverride the SQLite database filename (without path); used only when odbc-dsn is not setStringvoicemail_<profile_name>

MWI (Message Waiting Indicator):

ParameterPurposeAccepted ValuesDefault
send-full-vm-headerWhen true, the MWI Voice-Message SIP header includes urgent message counts in the format new/saved (new-urgent/saved-urgent) instead of the abbreviated new/saved formtrue, falsefalse

Email delivery (inline profile params, not inside <email>):

ParameterPurposeAccepted ValuesDefault
notify-email-bodyLiteral body text for notification-only emails when no template file is used; set as a <param> in the profile (outside <email>)String(none)
notify-email-headersLiteral RFC 2822 headers for notification-only emails; set as a <param> in the profile (outside <email>)String(none)

Web interface:

ParameterPurposeAccepted ValuesDefault
web-template-filePath to a template file used to generate a web-based voicemail interface responseFilename relative to the FreeSWITCH config directoryweb-vm.tpl

DTMF Key Bindings

These parameters assign DTMF digits to menu actions. Each accepts a single DTMF digit (0-9, *, #).

Main menu (mailbox check):

ParameterActionDefault
login-keysDigit(s) that prompt for mailbox ID at the start of a check session0
main-menu-keyReturn to the main menu0
play-new-messages-keyPlay new messages1
play-saved-messages-keyPlay saved messages2
config-menu-keyEnter configuration menu5

During message playback:

ParameterActionDefault
listen-file-keyListen to the current message1
save-file-keySave (move to saved folder)2
delete-file-keyDelete the message7
undelete-file-keyUndelete the message8
email-keyEmail the message to the subscriber4
callback-keyInitiate a callback call to the message sender5
forward-keyForward the message to another mailbox8
prepend-keyPrepend a recording to the message before forwarding1
urgent-keyMark the message as urgent during leave-message recording*
previous-message-keyGo to previous message1
next-message-keyGo to next message3
repeat-message-keyRepeat the current message0
skip-info-keySkip envelope information*
pause-keyPause/resume playback0
restart-keyRestart message from beginning1
ff-keyFast-forward6
rew-keyRewind4

During greeting (caller side):

ParameterActionDefault
skip-greet-keySkip the greeting and go directly to record tone#
operator-keyTransfer to operator-extension(empty; disabled)

Configuration menu:

ParameterActionDefault
record-greeting-keyRecord a new greeting1
choose-greeting-keySelect among recorded greetings2
record-name-keyRecord the subscriber name3
change-pass-keyChange the mailbox PIN6

Recording sub-menu (when recording a greeting):

ParameterActionDefault
record-file-keyStart recording3
listen-file-keyListen to recording1
save-file-keySave the recording2

Email Sub-element

Email delivery parameters are nested inside an <email> child element within the profile. The <email> block supports <param> elements and two special raw-text children, <body> and <headers>:

<email>
<param name="template-file" value="voicemail.tpl"/>
<param name="notify-template-file" value="notify-voicemail.tpl"/>
<param name="date-fmt" value="%A, %B %d %Y, %I:%M %p"/>
<param name="email-from" value="${voicemail_account}@${voicemail_domain}"/>
<!-- Optional: inline body and headers instead of template files -->
<!-- <body>Voicemail from ${voicemail_caller_id_name}</body> -->
<!-- <headers>X-Custom-Header: value</headers> -->
</email>

<email> <param> reference:

ParameterPurposeAccepted ValuesDefault
template-fileTemplate file for the email sent with an attached message audio fileFilename relative to the FreeSWITCH config directoryvoicemail.tpl
notify-template-fileTemplate file for the notification-only email (no audio attachment)Filename relative to the FreeSWITCH config directorynotify-voicemail.tpl
date-fmtstrftime(3) format string used to render ${voicemail_time} in templatesstrftime format string%A, %B %d %Y, %I:%M %p
email-fromFrom address for outbound voicemail email; supports channel variable expansionEmail address or expression${voicemail_account}@${voicemail_domain}

<email> raw-text children:

ElementPurpose
<body>Literal email body text used in place of a template file for message delivery emails
<headers>Literal RFC 2822 header lines appended to the outgoing message delivery email

When <body> is present, it overrides the template-file for the delivery email. When <headers> is present, those header lines are included in the outgoing email. Both elements support ${variable} expansion.

Template files are located in the FreeSWITCH configuration root (the same directory as voicemail.conf.xml). The vanilla configuration ships voicemail.tpl (message delivery with attachment) and notify-voicemail.tpl (notification only, no attachment). Both are RFC 2822 formatted MIME multipart documents with plain text and HTML parts.

Storage and Database Options

By default, mod_voicemail uses an SQLite database to store message metadata and places recorded audio files under the global FreeSWITCH storage directory in a voicemail/ subdirectory, organized as voicemail/<domain>/<mailbox-id>/.

Setting storage-dir in the profile overrides the storage root:

<param name="storage-dir" value="/var/lib/freeswitch/voicemail"/>

When storage-dir-shared is false (the default), the layout under storage-dir is <domain>/<mailbox-id>/. When true, it is <domain>/voicemail/<mailbox-id>/.

For ODBC storage of message metadata:

<param name="odbc-dsn" value="voicemail:fsuser:fspassword"/>

Per-user storage overrides are available via the user directory parameters vm-storage-dir and vm-domain-storage-dir (see Section 19.3.1). The user-level vm-domain-storage-dir parameter supersedes the profile storage-dir. The older per-user storage-dir variable is deprecated; use vm-domain-storage-dir instead.


User Directory Integration

Each voicemail mailbox corresponds to a user entry in the FreeSWITCH XML user directory (typically under directory/default/). The mailbox ID is the user's id attribute. The vm-password param in the user's <params> block sets the PIN required to authenticate during mailbox check.

<user id="1000">
<params>
<param name="password" value="$${default_password}"/>
<param name="vm-password" value="1000"/>
</params>
</user>

When db-password-override is false in the profile (the default), the directory vm-password is authoritative. When set to true, a password stored in the voicemail database (set by the subscriber via the change-password menu) takes precedence.

Per-User Parameters

The following <param> entries in a user's directory entry override profile-level behavior for that mailbox:

ParameterPurpose
vm-passwordMailbox PIN
vm-mailtoEmail address to deliver voicemail messages with audio attachment
vm-notify-mailtoEmail address for notification-only delivery (no audio attachment)
vm-mailfromOverride the From address for this user's voicemail email
vm-ccCC address added to the voicemail delivery email
vm-email-all-messagesSet to true to email every new message automatically
vm-notify-email-all-messagesSet to true to send a notification email for every new message
vm-attach-fileSet to true to attach the audio file to the delivery email
vm-keep-local-after-emailSet to true to retain the local message file after emailing
vm-storage-dirPer-user override for the audio file storage path
vm-domain-storage-dirPer-user override for the domain-level storage path
vm-message-extOverride the file extension (audio format) for this user's messages
vm-enabledSet to false to disable voicemail for this user
vm-disk-quotaMaximum total storage in bytes allowed for this mailbox
vm-alternate-greet-idUse a different mailbox ID's greeting when leaving a message for this user
vm-operator-extensionPer-user operator extension, overriding the profile-level setting
vm-skip-instructionsSet to true to skip the post-greeting recording instructions for this user
vm-convert-cmdOverride the audio conversion command for this user
vm-convert-extOverride the converted file extension for this user
timezoneTimezone used to render ${voicemail_time} in email templates; set in <variables> or <params>

The voicemail Dialplan Application

The application name is voicemail; it is also summarized in the dptools reference. The full argument syntax is:

[check] [auth] [auth_only] <profile_name> <domain_name> [<id>] [uuid]

profile_name and domain_name are required. id is the mailbox identifier; when omitted, the module reads the channel variable voicemail_id. If profile_name or domain_name is missing from the argument string, the module reads voicemail_profile_name and voicemail_domain_name channel variables respectively.

The optional keywords check, auth, and auth_only are parsed in order before the positional arguments. They are case-insensitive. Multiple keywords can appear together (e.g., check auth).

Leave-Message Mode

When neither check nor auth_only is specified, the application runs in leave-message mode: it plays the mailbox owner's greeting, records a message from the caller, and stores the recording.

<!-- Leave a message in mailbox 1001, profile "default", domain "example.com" -->
<action application="voicemail" data="default example.com 1001"/>

A typical use is as a post-bridge fallback when a called extension is unavailable:

<action application="bridge" data="user/1001@example.com"/>
<action application="voicemail" data="default ${domain_name} 1001"/>

Check-Mailbox Mode

When check is present, the application enters mailbox check mode: the subscriber is prompted to enter their mailbox ID (if not supplied in the argument) and PIN, then presented with the message playback menu.

<!-- Prompt for mailbox ID and PIN -->
<action application="voicemail" data="check default ${domain_name}"/>

<!-- Pre-supply the mailbox ID; subscriber still enters PIN -->
<action application="voicemail" data="check default ${domain_name} 1001"/>

The auth keyword bypasses PIN authentication, treating the caller as already authenticated. This is appropriate when the subscriber is calling from their own registered extension and the dialplan has verified identity:

<action application="voicemail" data="check auth default ${domain_name} ${dialed_extension}"/>

The auth_only keyword causes the session to enter check mode and exit immediately after successful PIN authentication, without presenting the message menu. This is useful for two-factor flows or PIN verification integrations. The auth_only keyword implies check mode; check does not need to be specified alongside it.

<action application="voicemail" data="auth_only default ${domain_name} ${dialed_extension}"/>

The optional uuid positional argument (after the mailbox id) is only meaningful in check mode. When supplied, it opens a specific message directly by UUID.

Channel Variables

Input variables (read before or during execution):

VariablePurpose
voicemail_profile_nameProfile name fallback when not supplied in the argument string
voicemail_domain_nameDomain name fallback when not supplied in the argument string
voicemail_idMailbox ID fallback when not supplied in the argument string
voicemail_authorizedWhen set to true, the subscriber is treated as authenticated (equivalent to the auth keyword)
vm_auth_onlyWhen set to true inside an active check-mode session, the session exits after successful authentication
skip_greetingWhen set to true before invoking leave-message mode, the mailbox owner's greeting is skipped; cleared after use
skip_instructionsWhen set to true before invoking leave-message mode, the post-greeting recording instructions are skipped; cleared after use
skip_record_urgent_checkWhen set to true, the urgent-message prompt at the end of leave-message recording is suppressed; cleared after use
voicemail_skip_goodbyeWhen set to true, the goodbye prompt at the end of leave-message mode is suppressed; cleared after use
vm_ccComma-separated list of additional mailbox addresses to copy the message to after delivery

Output variables (set by the module after execution):

VariablePurpose
voicemail_accountMailbox ID (user ID) of the destination mailbox
voicemail_domainDomain of the destination mailbox
voicemail_caller_id_nameCaller ID name of the message sender
voicemail_caller_id_numberCaller ID number of the message sender
voicemail_formatted_caller_id_numberFormatted (localized) version of the caller ID number
voicemail_file_pathAbsolute path to the recorded message file
voicemail_message_lenDuration of the recorded message in seconds
voicemail_read_flagsRead state flags for the message
voicemail_timeMessage timestamp formatted per the date-fmt profile setting
voicemail_priorityMessage priority value (maps to X-Priority header in email)
voicemail_emailDelivery email address (vm-mailto) for the mailbox owner
voicemail_email_fromFrom address used for the voicemail delivery email
voicemail_notify_emailNotification email address (vm-notify-mailto) for the mailbox owner
voicemail_current_folderName of the current message folder (new or saved)
voicemail_total_new_messagesTotal count of new (unread) messages in the mailbox
voicemail_total_saved_messagesTotal count of saved messages in the mailbox
voicemail_urgent_new_messagesTotal count of urgent new messages in the mailbox
voicemail_urgent_saved_messagesTotal count of urgent saved messages in the mailbox
user_pin_authenticatedSet to true after successful PIN authentication in auth_only mode
user_pin_authenticated_userMailbox ID of the user who authenticated in auth_only mode

Email Notification

When a new message is left and the user directory has vm-mailto or vm-notify-mailto configured, mod_voicemail generates and sends an email using FreeSWITCH's internal switch_simple_email function. The host must have a working MTA (such as sendmail or postfix) installed and accessible from the default PATH.

Two delivery modes exist:

  • Message delivery (vm-mailto + vm-attach-file true): The email is rendered using the profile template-file and includes the recorded audio as a MIME attachment.
  • Notification only (vm-notify-mailto): The email is rendered using notify-template-file with no attachment. The notify-voicemail.tpl template differs from voicemail.tpl only in that it addresses ${voicemail_notify_email} rather than ${voicemail_email}.

Setting vm-notify-email-all-messages true on the user triggers a notification email for every inbound message automatically, without requiring the subscriber to configure forwarding interactively.

Audio format conversion before attachment is available via vm-convert-cmd and vm-convert-ext (or the profile-level equivalents convert-cmd and convert-ext). The convert command is called as a shell command with the source file path; the resulting file with the new extension is attached.

Email Template Variables

Templates are plain RFC 2822 text files with FreeSWITCH variable substitution (${variable}). The following variables are populated by the module for use in template files:

VariableContent
${voicemail_caller_id_name}Caller ID name of the message sender
${voicemail_caller_id_number}Caller ID number of the message sender
${voicemail_domain}Domain of the mailbox
${voicemail_account}Mailbox ID (user ID)
${voicemail_email}Delivery email address (vm-mailto)
${voicemail_email_from}From address for the delivery email (vm-mailfrom or profile email-from)
${voicemail_notify_email}Notification email address (vm-notify-mailto)
${voicemail_time}Message timestamp formatted per the date-fmt profile setting
${voicemail_message_len}Duration of the recorded message in seconds
${voicemail_priority}Message priority value; maps to X-Priority header
${voicemail_read_flags}Read state flags for the message
${voicemail_total_new_messages}Total new (unread) message count for the mailbox
${voicemail_total_saved_messages}Total saved message count for the mailbox
${RFC2822_DATE}Current date and time in RFC 2822 format

The default voicemail.tpl produces a multipart/alternative message with plain text and HTML parts. The HTML part includes a tel: URI link on the caller number. The notify-voicemail.tpl template addresses ${voicemail_notify_email} instead of ${voicemail_email} and sends no audio attachment. Both templates ship as files in the FreeSWITCH configuration root and can be edited freely.


Default Dialplan Entries

The vanilla dialplan/default.xml ships with two voicemail-related extension patterns.

Leave a message (post-bridge fallback):

When a local extension does not answer, the dialplan bridges to the voicemail application in leave-message mode using a loopback channel:

<action application="bridge" data="loopback/app=voicemail:default ${domain_name} ${dialed_extension}"/>

This pattern appears in the Local_Extension and Local_Extension_Skinny extensions.

Mailbox check (vmain extension):

<extension name="vmain">
<condition field="destination_number" expression="^vmain$|^4000$|^\*98$">
<action application="answer"/>
<action application="sleep" data="1000"/>
<action application="voicemail" data="check default ${domain_name}"/>
</condition>
</extension>

This extension matches destination numbers vmain, 4000, and *98. After answering and a brief 1-second sleep, it invokes the voicemail application in check mode with the default profile. Because no mailbox ID is supplied, the subscriber is prompted to enter their mailbox number followed by their PIN.

To restrict mailbox check to a subscriber's own extension (pre-authenticated), set the voicemail_authorized channel variable to true before invoking the application, or include the auth keyword in the application data.


Global Settings

The <settings> block at the top level of voicemail.conf.xml (outside any profile) accepts module-wide parameters:

<settings>
<param name="message-query-exact-match" value="false"/>
</settings>
ParameterPurposeAccepted ValuesDefault
message-query-exact-matchWhen true, the vm_count API and related queries match the domain field exactly. Operators who use distinct domain names per tenant must enable this and define a dedicated profile per domain.true, falsefalse
debugEnables additional debug logging for the moduleInteger (0 = off)0