Skip to main content

Sending Bulk SMS from CSV

Overview

This application will show how you can use SignalWire and the Python SDK to easily send bulk SMS through a simple script with minimal modifications. This script will read in a CSV of customer data and pull the phone numbers/first names in order to send out messages. When the full send is complete, this script will store the message data in a CSV.

What do I need to run this code?

You will need the SignalWire Python SDK as well as your authentication variables which can easily be found in the API tab of your SignalWire Space. View here to see more about navigating your Space and how to find authentication variables.

In order to store the message data and export to a CSV, you will need the pandas library.

Full code example: Bulk SMS - Python
import pandas as pd
from signalwire.rest import Client as signalwire_client
import csv
import time

# import client
client = signalwire_client("ProjectID", "AuthToken", signalwire_space_url = 'example.signalwire.com')

# define results dict for storing client records from csv and messages list for storing data about send
results = {}
messages = []

# link placeholder if links need to be sent with the message
# use results[customer] to query database by phone number if customized URLs are needed
smsLink = "https://developer.signalwire.com/"

# read in CSV to dict where phone number is the key and [first name, last name] is the value
with open("src/bulk_sms.csv", 'r', encoding='utf-8-sig') as file:
reader = csv.DictReader(file)
for row in reader:
results[row['Number']] = [row['First'], row['Last']]
print(results)

# loop through entries and grab first name
for customer in results:
# store name for matched phone number in variable to use in template
firstName = (results[str(customer)][0])
print(f"messaging {firstName}")

# set formatted number to the E164 version using ternary operator
formattedNumber = "+" + customer if "+" not in customer else customer

# send message
message = client.messages.create(
from_='+1xxxxxxxxxx',
body=f"Hello {firstName}, you can access our developer portal at {smsLink} ",
to=formattedNumber)

messages.append((message.sid, message.from_, message.to, message.body, message.date_sent))
# sleep for 1 second in order to rate limit at 1 messag per second - adjust based on your approved campaign throughput
time.sleep(1)

# Puts call log array into dataframe with headers for easier reading.
df = pd.DataFrame(messages, columns=('Sid', 'From', 'To', 'Body', 'Date/Time Sent'))

print(df.to_string)

df.to_csv('BulkSendDetails.csv', index=False, encoding='utf-8')

Step by Step Code Content

Customer Data CSV

The first thing you will need is a CSV with customer data in the format of first name, last name, and phone number, like shown below:

First,Last,Number
Eleanor,Shellstrop,+1xxxxxxxxxx
Chidi,Anagonye,1xxxxxxxxxx
Tahani,Al-Jamil,1xxxxxxxxxx
Jason,Mendoza,1xxxxxxxxxx

The correct country code must be included for the number to be routed correctly. You can find the correct code by country here.

main.py

The first step for using any of our Compatibility APIs is to import the SignalWire library and authenticate the client. We will also import pandas and csv here.

import pandas as pd
from signalwire.rest import Client as signalwire_client
import csv
import time

# import client
client = signalwire_client("ProjectID", "AuthToken", signalwire_space_url = 'example.signalwire.com')

In the next step, we define a dictionary results to store customer data and a messages list for storing each message record sent. We will open the CSV (make sure to correct the path in your code) and read each file into our results dictionary using the phone number as the key and the first name/last name as the value.

If your messaging needs a link, you can use the smsLink variable to point to it or point to the dynamically generated URL through a query to your database.

# define results dict for storing client records from csv and messages list for storing data about send
results = {}
messages = []

# read in CSV to dict where phone number is the key and [first name, last name] is the value
with open("src/bulk_sms.csv", 'r', encoding='utf-8-sig') as file:
reader = csv.DictReader(file)
for row in reader:
results[row['Number']] = [row['First'], row['Last']]
print(results)

# link placeholder if links need to be sent with the message
# use results[customer] to query database by phone number if customized URLs are needed
smsLink = "https://example.com/"

Our next section will loop through each of the results customers and store the first name and formatted phone number into variables. If the original number is not in E164 format (including the + in front of the country code), we will assign the E164 version to the formattedNumber variable. We will then send the message and append the message data to the messages array. If you do not need a link, change the template to not include smsLink.

# loop through entries and grab first name
for customer in results:
# store name for matched phone number in variable to use in template
firstName = (results[str(customer)][0])
print(f"messaging {firstName}")

# set formatted number to the E164 version using ternary operator
formattedNumber = "+" + customer if "+" not in customer else customer

# send message
message = client.messages.create(
from_='+1xxxxxxxxxx',
body=f"Hello {firstName}, you can access our developer portal at {smsLink} ",
to=formattedNumber)

messages.append((message.sid, message.from_, message.to, message.body, message.date_sent))
# sleep for 1 second in order to rate limit at 1 messag per second - adjust based on your approved campaign throughput
time.sleep(1)

Lastly, now that the bulk send is over, we will store the messages data in a pandas dataframe and export to CSV.

# Puts call log array into dataframe with headers for easier reading.
df = pd.DataFrame(messages, columns=('Sid', 'From', 'To', 'Body', 'Date/Time Sent'))

print(df.to_string)

df.to_csv('BulkSendDetails.csv', index=False, encoding='utf-8')

Sign Up Here

If you would like to test this example out, create a SignalWire account and Space.

Please feel free to reach out to us on our Community Slack or create a Support ticket if you need guidance!