In this blog, we will guide you through the process of building an automated dialer application using Asterisk/Issabel. The application will allow you to upload a CSV file with telephone numbers, process the data using Python scripts, and initiate the dialing process through the Asterisk Management Interface (AMI).
Prerequisites:
It is assumed that you already have an Asterisk or Issabel PBX installed and configured. Additionally, you should have an active SIP trunk provided by a telecommunications provider. It is also important to have a basic understanding of Asterisk and how to write an Asterisk dialplan. However, don’t worry, as we will provide you with a complete dialplan that you can use.
Furthermore, you will need a basic understanding of Linux commands as well as some knowledge of Python programming. These skills will be helpful in following the steps outlined in this tutorial.
Solution Components
1. Web Interface for CSV Upload:
To start, we guide you to develop a user-friendly web interface where you can upload a CSV file containing a list of telephone numbers. The interface is built using PHP, making it simple to interact with. Once the CSV file is uploaded, it gets stored in a designated Linux directory.
2. Python Script for Data Processing:
To automate the process, we shall write a Python script (csv_processing.py) that executes at regular intervals using a cronjob. This script reads the uploaded CSV file and performs two essential tasks. First, it saves the telephone numbers to a MySQL table. Second, it deletes the CSV file.
3. Python Script for Dialing and AMI Integration:
Another Python script (dialer_manager.py), running every five minutes through a cronjob, takes charge of selecting numbers in pending status from the MySQL table. Using the Asterisk Management Interface (AMI), the script initiates the dialing process, sending the selected numbers to the Asterisk dialer.
4. Asterisk Dialplan
The Asterisk dialplan is a set of instructions that is executed once the call is answered. In this case, the dialplan will play a voice recording to the caller and then end the call. Additionally, the details of the call will be saved to another MySQL table.
If you’re feeling overwhelmed, don’t worry! We’re here to guide you through each step in building a complete automated dialer application. Let’s get started!
Comprehensive Walkthrough
1. Web Interface for CSV Upload:
In this section, we will create a PHP page to make it easy for users to upload a CSV file that contains telephone numbers. The upload.php serves as the web interface where users can perform the CSV file upload. Below is the source code for upload.php:
<?php
if(isset($_FILES['file'])) {
$targetDir = "/var/www/html/dialer/";
$targetFile = $targetDir . "numbers.csv";
if(move_uploaded_file($_FILES['file']['tmp_name'], $targetFile)) {
echo "File uploaded and renamed successfully.";
} else {
echo "Error uploading file: " . $_FILES['file']['error'];
}
}
?>
<!DOCTYPE html>
<html>
<head>
<title>CSV File Upload</title>
</head>
<body>
<form method="POST" enctype="multipart/form-data">
<input type="file" name="file" accept=".csv">
<input type="submit" value="Upload">
</form>
</body>
</html>
**** Special Note
Please note that it’s important to incorporate relevant authentication mechanisms to your PHP page, such as a username and password, to restrict unauthorized access. Without proper security measures in place, anyone can upload a CSV file and initiate outbound dialing, potentially resulting in substantial call charges. Therefore, it is crucial to pay full attention to securing your upload.html page in production environments.
To make upload.php file accessible through a web browser, you need to save it in a specific web directory on your Asterisk server. In Issabel, a CentOS-based PBX system, the web directory where you can save the upload.php files is typically located at /var/www/html/. This is the default web directory for serving web pages.
In our example, we decided to create a subdirectory called “dialer” within the “/var/www/html/” directory.
mkdir /var/www/html/dialer
This subdirectory serves as a dedicated space for our files related to the dialer application. By choosing this approach, we ensure that our files are stored separately from other files in the web root directory, allowing for better organization and easier management of our dialer-related files.
You can use an FTP client to access the server and navigate to the /var/www/html/dialer directory. Within this directory, you can save the upload.php file.
Remember to set proper permissions for the files and directories to ensure they are readable and executable by the web server.
To access your upload.php
file through a web browser, you can use the following URL: http://<Your Asterisk IP>/dialer/upload.php
. Please remember to replace <Your Asterisk IP>
with the correct IP address or DNS name of your Asterisk server. By entering this URL in your web browser, you will be able to view and interact with the upload.php
file.
If you encounter an error message like “Error uploading file:”, it may be due to incorrect ownership and permissions set for the “dialer” directory. To resolve this, you’ll need to determine the user who owns the web server process. You can use the command “ps aux | grep httpd” to find this information. If you are using Issabel, the web server is likely running under the “asterisk” user.
To set the correct ownership and permissions, execute the following commands.
sudo chown asterisk:asterisk /var/www/html/dialer
sudo chmod 755 /var/www/html/dialer
These commands will change the ownership of the “dialer” directory to the “asterisk” user and group, and set the permissions to allow read, write, and execute for the owner, and read and execute for others. By performing these steps, you should be able to resolve any issues related to file uploading in the “dialer” directory.
When selecting your CSV file containing telephone numbers, it’s important to ensure that the numbers are in the required format based on your country. In the case of the USA, you need to verify the correct format for both interstate and local calls. Keep in mind that the format may vary for other countries as well, so it’s crucial to verify the correct format before entering the numbers into the CSV file. This helps ensure that the dialer application functions properly and accurately handle the calls for your specific country.
Once uploaded, the csv file will be saved to /var/www/html/dialer directory and renamed to numbers.csv.
Create MySQL Table
To save the telephone numbers in a MySQL table, you need to create a table named number_list
with the following columns:
id
: Auto Increment id.created_time
: This column should be of typeDATETIME
to store the date and time of record insertion.telephone_number
: This column should be of typeNVARCHAR
to store the telephone numbers as text.dial_status
: This column should also be of typeNVARCHAR
with a default value of'pending'
. It keeps track of the status of the dialing process.dial_time
: This column should be of typeDATETIME
to store the date and time when the dialing action occurred.tries
: This column should be of typeINTEGER
with a default value of 0. It counts the number of attempts made for dialing.
CREATE TABLE number_list (
id INT AUTO_INCREMENT PRIMARY KEY,
created_time DATETIME,
telephone_number NVARCHAR(255),
dial_status NVARCHAR(255) DEFAULT 'pending',
dial_time DATETIME,
tries INT DEFAULT 0
);
By creating the number_list
table with these columns, you can efficiently store the telephone numbers along with their corresponding dialing status, timestamp, and number of tries. This allows for effective tracking and management of the dialing process in the MySQL database.
2. Python Script for Data Processing:
To automate the process, we utilize a Python script called “csv_processing.py”. This script runs at scheduled intervals through a cronjob. Its purpose is to streamline the process by performing two crucial tasks.
Firstly, the script reads the uploaded CSV file numbers.csv, extracting the telephone numbers from it. These numbers are then saved into a MySQL table.
Secondly, after successfully saving the numbers, the script takes care of deleting the CSV file. This step helps maintain a clean and organized data handling process, removing unnecessary files once the relevant information has been extracted and stored.
You have the flexibility to save the csv_processing.py file in any directory you prefer, and it is not necessary to save it in the web root or a specific subdirectory. In this example, we choose to save it in a subdirectory named “scripts” within the “/root” directory.
The complete path to the file would be “/root/scripts/csv_processing.py”. Create dialer directory using the command “mkdir /root/dialer” before copying the file. Here is the source code for csv_processing.py:
import csv
import os
import pymysql
# Database connection details
db_host = 'localhost'
db_user = 'your_username'
db_password = 'your_password'
db_name = 'your_database_name'
# Path to the CSV file
csv_file_path = '/var/www/html/dialer/numbers.csv'
# Connect to the database
db_connection = pymysql.connect(host=db_host, user=db_user, password=db_password, db=db_name)
try:
# Create a database cursor
cursor = db_connection.cursor()
# Read the CSV file
with open(csv_file_path, 'r') as file:
csv_reader = csv.reader(file)
# Iterate over each row in the CSV file
for row in csv_reader:
telephone_number = row[0] # Assuming the telephone number is in the first column of the CSV
# Save the telephone number to the database table
query = f"INSERT INTO number_list (telephone_number,created_time) VALUES ('{telephone_number}',now())"
cursor.execute(query)
# Commit the changes to the database
db_connection.commit()
# Close the database cursor and connection
cursor.close()
db_connection.close()
# Delete the CSV file
os.remove(csv_file_path)
print("CSV processing completed successfully!")
except Exception as e:
print("An error occurred during CSV processing:", str(e))
Please modify the MySQL database connection details in the csv_processing.py script according to your specific environment. Update the following information to match your MySQL database configuration:
db_host: Change this variable to the hostname or IP address of your MySQL database server.
db_user: Update this variable with the username used to connect to your MySQL database.
db_password: Change this variable to the password associated with the specified db_user.
db_name: Update this variable with the name of your MySQL database.
By making these changes, the csv_processing.py script will connect to your MySQL database using the correct credentials and interact with the appropriate database.
To run Python scripts in virtual environments on CentOS, you can follow these steps:
#Install Python's virtual environment package:
cd /root/scripts
sudo yum install python3-virtualenv
#Create a new virtual environment:
python3 -m venv myenv
#This will create a new directory named myenv that contains the isolated environment.
#Activate the virtual environment:
source myenv/bin/activate
#Once activated, your command prompt will change to reflect the virtual environment.
#Install the required dependencies for your Python script using pip:
#pip3 install <package_name>
#Replace <package_name> with the name of the package(s) required by your script. You can specify multiple packages separated by spaces.
#To Install pymysql package which is required to interact with MySQL Database.
pip3 install pymysql
#Run your Python script:
python csv_processing.py
By utilizing virtual environments, you can isolate the execution environment for your Python scripts, ensuring that the module versions and dependencies do not conflict with each other.
To automate the execution of csv_processing.py every minute on Linux, we need to create a shell script called csv_processing.sh. This script will change the directory to /root/scripts, run csv_processing.py in the background, and save the output to a file called csv_processing.log in the same directory.
Here’s an example of the csv_processing.sh shell script that changes the directory to /root/scripts, runs the csv_processing.py script in the background, and redirects the output to a csv_processing.log file in the same directory.
#!/bin/bash
# Change directory to /root/scripts
cd /root/scripts
#Activate virtual environment
source myenv/bin/activate
# Run csv_processing.py in the background and redirect the output to csv_processing.log
python csv_processing.py >> csv_processing.log &
Make sure to save this script as csv_processing.sh in the desired directory (/root/scripts in this case). Then, you can set up a cronjob to run this script every one minute.
To set up the cronjob, you can use the following command:
crontab -e
This will open the cronjob configuration file. Add the following line at the end to schedule the csv_processing.sh script to run every one minute:
* * * * * sh /root/scripts/csv_processing.sh
Save the file and exit the editor. The cronjob is now set to execute the csv_processing.sh script every minute. The script will change the directory, run the csv_processing.py script in the background, and store the output in the csv_processing.log file.
3. Python Script for Dialing and AMI Integration:
The final Python script, called dialer_manager.py
, runs every five minutes through a cronjob. It is responsible for selecting numbers with a “pending” status and a value of tries less than 3 from the number_list
table in MySQL. Using the Asterisk Management Interface (AMI), the script initiates the dialing process by sending the selected numbers to the Asterisk dialer.
Additionally, this Python program defines the Asterisk context as “YOUR_CONTEXT” with the extension “s” and priority 1. These settings determine the flow of the call once it is answered. Furthermore, the CALLERID for the outbound call is set to a specific value. Please make sure that your SIP Trunk Provider allows the use of the CALLERID value for making outbound calls.
In this updated version, the script also increments the value of the tries field by one each time it processes a number.
import pymysql
from asterisk.ami import AMIClient, SimpleAction
# MySQL connection details
mysql_host = 'localhost'
mysql_user = 'your_username'
mysql_password = 'your_password'
mysql_db = 'your_database_name'
# Asterisk AMI connection details
asterisk_host = 'localhost'
asterisk_user = 'your_ami_username'
asterisk_password = 'your_ami_password'
# Connect to MySQL
mysql_conn = pymysql.connect(
host=mysql_host,
user=mysql_user,
password=mysql_password,
db=mysql_db
)
# Connect to Asterisk AMI
ami_client = AMIClient(address=asterisk_host, port=5038)
ami_client.login(username=asterisk_user, secret=asterisk_password)
# Retrieve numbers with caller IDs from MySQL table
def get_phone_numbers():
cursor = mysql_conn.cursor()
cursor.execute("SELECT telephone_number, tries FROM number_list WHERE dial_status != 'ANSWERED' AND tries < 3")
rows = cursor.fetchall()
cursor.close()
return [row[0] for row in rows]
# Place outbound calls
def place_outbound_calls(phone_numbers):
for number in phone_numbers:
print(number)
action = SimpleAction(
'Originate',
Channel='SIP/YOUR_SIP_TRUNK_NAME/{0}'.format(number),
Context='YOUR_CONTEXT', # Replace with your desired context
Exten='s', # Replace with the extension within the context
Priority=1,
CallerID='YOUR_CALLERID',
Variable='MY_VARIABLE={0}'.format(number)
)
response = ami_client.send_action(action)
update_table(number)
print('Call to {0} initiated. Response: {1}'.format(number, response))
def update_table(number):
# Open a cursor
cursor = mysql_conn.cursor()
# Update statement
update_query = f"UPDATE number_list SET dial_status = 'in_progress',dial_time=now(), tries = tries + 1 WHERE telephone_number = '{number}'"
try:
# Execute the update statement
cursor.execute(update_query)
# Commit the changes to the database
mysql_conn.commit()
print("Table updated successfully.")
except pymysql.Error as e:
# Rollback the transaction if an error occurs
mysql_conn.rollback()
print("Error occurred during table update:", str(e))
finally:
# Close the cursor
cursor.close()
# Main program
if __name__ == '__main__':
numbers = get_phone_numbers()
place_outbound_calls(numbers)
# Close connections
mysql_conn.close()
ami_client.logoff()
You might need to install Python package ‘asterisk-ami’ in your Python virtual environment using below command.
pip3 install asterisk-ami
Please note that you will need to update the relevant parts of the code, such as the database connection details, AMI credentials, and the YOUR_SIP_TRUNK_NAME, YOUR_CONTEXT, YOUR_CALLERID to match your specific environment.
To find the Asterisk AMI (Asterisk Manager Interface) credentials in Issabel, you can follow these steps:
- Login to your Issabel administration panel.
- Navigate to the “PBX” tab.
- From the drop-down menu, select “Advanced Configuration”.
- In the left sidebar, click on “Asterisk File Editor”.
- Look for the file named “manager.conf” and click on it to open it.
- Within the “manager.conf” file, you should see the AMI credentials section. It typically starts with a heading like “[admin]” or “[your_username]”.
- Take note of the “username” (e.g. admin) and “secret” values for your AMI credentials.
Please note that accessing and modifying the configuration files should be done with caution, as it can affect the functionality of your Issabel system.
To run the dialer_manager.py
script every 5 minutes, you should save it in the /root/scripts
directory. Additionally, you will need to create a shell script called dialer_manager.sh
to execute this script through a cronjob. The process for setting up the dialer_manager.sh
script is the same as the steps you followed for csv_processing.sh
.
#!/bin/bash
# Change directory to /root/scripts
cd /root/scripts
#Activate virtual environment
source myenv/bin/activate
# Run dialer_manager.py in the background and redirect the output to dialer_manager.log
python dialer_manager.py >> dialer_manager.log &
You Also need to add following line at the end of your crontab.
* /5 * * * sh /root/scripts/dialer_manager.sh
4. Asterisk Dialplan
Now it’s time to create your Asterisk dialplan.
[YOUR_CONTEXT]
exten => s,1,Answer()
same => n,Set(cdr_number=${MY_VARIABLE})
same => n,Playback(/var/lib/asterisk/sounds/custom/YOUR_SOUND_FILE)
same => n,Hangup()
exten => h,1,MYSQL(Connect connid localhost your_username your_password your_database_name)
same => n,MYSQL(Query resultid2 ${connid} update number_list set dial_status='ANSWERED' where telephone_number='${cdr_number}')
same => n,MYSQL(Query resultid1 ${connid} INSERT INTO dial_results (telephone_number, dial_datetime, answer_status, call_duration) VALUES ('${cdr_number}', NOW(),'ANSWERED', ${CDR(duration)}))
same => n,MYSQL(Disconnect ${connid})
To add a new context to your dialplan, you can follow these steps:
- If you are using pure Asterisk, open the extensions.conf file located in the /etc/asterisk directory. If you are using Issabel, open the extension_custom.conf file in the same directory.
- Add the new context at the end of the file. You can give it a meaningful name that represents its purpose.
- Save the changes to the file.
- In your Asterisk Console, type the command ‘module reload’ to apply the changes and reload the dialplan.
By following these steps, you will successfully add a new context to your dialplan.
This dialplan will be executed once the call is answered. In this dialplan, we will use the Answer()
function to indicate that the call has been answered. Then, we will use the Playback()
function to play a voice prompt, which can be a marketing message or any other recorded message. Finally, we will use the Hangup()
function to disconnect the call.
The Dialplan will change the ‘dial_status’ of the ‘number_list’ table to ‘ANSWERED’. This is done to make sure that the dialer_manager.py doesn’t try those entries again in future retries.
Additionally, we will save the details of the calls in another MySQL table called dial_results
. This table will have several fields, including telephone_number
to store the phone number, dial_datetime
to record the date and time of the call, answer_status
to capture whether the call was answered or not, and call_duration
to store the duration of the call.
By saving this information in the dial_results
table, you can keep track of the call details for further analysis or reporting purposes.
Use below MySQL script to create ‘dial_results’ table.
CREATE TABLE dial_results (
id INT AUTO_INCREMENT PRIMARY KEY,
telephone_number VARCHAR(20),
dial_datetime DATETIME,
answer_status VARCHAR(20),
call_duration INT
);
Important points
When following this entire process of setting up an automated outbound dialer application using Asterisk, there are several important points to keep in mind:
- Understanding of Asterisk: It is essential to have a good understanding of Asterisk and how it works as an open-source PBX software. Familiarize yourself with its features, configurations, and dialplan scripting.
- Knowledge of Linux: Basic knowledge of Linux commands and file system navigation is necessary to work with the Linux distributions such as CentOS or Issabel, where Asterisk is being installed.
- Security Considerations: Ensure that appropriate security measures are in place to protect your system and prevent unauthorized access. Implement authentication mechanisms, such as username/password, to restrict access to sensitive components like the web interface.
- Validation of CSV Format: Before uploading a CSV file containing telephone numbers, ensure that the file is in the correct format, specific to your country’s dialing rules. Verify the format for interstate or local calls, as it may vary. Incorrect formatting could lead to issues in outbound dialing.
- Database Configuration: Set up the MySQL/MariaDB database and configure the necessary tables to store the telephone numbers and call details. Ensure that the database connection information is correctly specified in the Python scripts.
- Virtual Environments: Consider using virtual environments for running the Python scripts to isolate the execution environment and prevent module version conflicts. Refer to the relevant documentation or articles to set up virtual environments in CentOS.
- Testing and Troubleshooting: It is important to thoroughly test each component of the application, including file uploads, database connections, dialing process, and call flow. Monitor log files and error messages for any issues that may arise during the implementation.
- Regular Maintenance: Schedule regular maintenance tasks, such as cleaning up temporary files, optimizing the database, and monitoring system performance, to ensure smooth and efficient operation of the outbound dialer application.
- Compliance and Regulations: Depending on your location and industry, there may be specific compliance and regulatory requirements for outbound dialing, such as obtaining consent for making calls and adhering to do-not-call lists. Familiarize yourself with these regulations and ensure compliance.
- Documentation: Maintain thorough documentation of the entire setup, including configurations, scripts, and any customizations made. This documentation will be helpful for future reference, troubleshooting, and scaling the system if needed.
Exploring the Applications of Automated Dialing
The knowledge gained from this blog can be applied in various scenarios where you need to automate dialing processes or create an automated phone system. Here are a few potential applications:
- Call Centers: The knowledge can be applied to build an automated dialer system for call centers, where agents can upload a list of numbers to be dialed automatically, and the system can handle the dialing process, play recorded messages, and log call details.
- Telemarketing and Sales: Businesses engaged in telemarketing or sales can use this knowledge to automate their outbound calling processes. They can upload a list of leads or prospects, and the system can automatically dial the numbers, play sales pitches or recorded messages, and track call outcomes.
- Appointment Reminders: Medical clinics, service providers, or any business that schedules appointments can utilize this knowledge to build an automated system that calls customers to remind them of their upcoming appointments. The system can play pre-recorded messages and allow customers to confirm or reschedule their appointments.
- Voice Broadcasting: Political campaigns, community organizations, or businesses needing to broadcast important messages can apply this knowledge to create a voice broadcasting system. The system can automatically dial a list of phone numbers and play a recorded message to deliver information, announcements, or alerts.
- Customer Service and Support: Companies that provide customer service or support can leverage this knowledge to automate their inbound call routing and handling. The system can be configured to route incoming calls based on predefined rules, play interactive voice response (IVR) menus, and connect callers to the appropriate agents or departments.
- Interactive Phone Surveys: Researchers or organizations conducting phone surveys can use this knowledge to build an automated system that dials numbers, plays survey questions or prompts, records responses, and collects data for analysis.
These are just a few examples of where the knowledge from this blog can be applied. The ability to automate dialing processes and integrate with Asterisk opens up opportunities for streamlining communication, improving efficiency, and enhancing customer experiences in various industries.
Following the steps carefully, you can successfully set up and operate an automated outbound dialer application using Asterisk.
If you encounter any issues or problems while following the steps, please feel free to comment here or send us an email at info@callxtra.com. We are more than happy to assist you and help resolve any concerns you may have. If you require technical support for your Asterisk installation, we offer free consultations to provide assistance.
We would also love to hear about your success stories in implementing automated dialing by following this guide. Share your achievements with us and let us know how this process has benefited your operations. Your feedback and success stories are important to us.