Send WhatsApp Messages From Google Sheets Using C# (.NET)
In this tutorial, you’ll learn how to send messages to phone numbers stored in a Google Sheets CSV file using C# and Wassenger API. We will download the CSV file from Google Sheets, read the phone numbers and send messages through your WhatsApp number
How to automate WhatsApp with AI
Prerequisites
- Basic understanding of C# (.NET): Familiarity with programming in C# and handling HTTP APIs.
- .NET Installed: Ensure the .NET SDK is installed on your computer. You can download it from Microsoft’s .NET website.
- NuGet Packages: Install the following libraries:
- CsvHelper: Parsing CSV files downloaded from Google Sheets.
- RestSharp: HTTP requests to the Wassenger API. - Wassenger API Token: You can obtain your API token from Wassenger by signing up, creating a workspace, and generating an API key.
- Google Sheets CSV Download URL: Publish your Google Sheets as a CSV file and copy the download URL. This requires enabling “Publish to the web” in Google Sheets and copying the link.
Install required packages
First, create a new directory for your project and navigate to it in your terminal. Then, run the following commands to install the necessary libraries:
Install Required Packages
- Create a new directory for your project:
mkdir WhatsAppMessaging cd WhatsAppMessaging
2. Initialize a new .NET project:
dotnet new console
3. Install the necessary NuGet packages:
- CsvHelper for reading CSV files:
dotnet add package CsvHelper
- RestSharp for handling HTTP requests:
dotnet add package RestSharp
Prepare the Google Sheets CSV file
Create a new Google Sheets document and fill it with two columns:
- First column: phone number in E164 format with the country prefix.
- Second column: text message to send to the target phone number.
The Google Sheets document should have at least two columns and look like:
The equivalent Sheets document exported as CSV should look like this:
+1234567890,"👋 Welcome to {{your-business-name}}! Thanks for signing up. We are just a message away!"
+1234567890,"💐 Your order has been shipped. Tracking number is {{tracking-number}}. Don't hesitate to reach out to if you need help! 🤗"
Get the download URL of your Google Sheets document
- Click on “File” in the top left corner.
- Go to “Share” > “Publish to the web”.
- In the “Link” tab, select “Comma-separated values (.csv)” from the dropdown menu.
- Select the desired sheet page with the relevant data: by default the first one.
- Click on “Publish” and copy the URL.
Send text messages
Create a new file named sendMessages.cs
in your project directory and add the following code:
using CsvHelper;
using RestSharp;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
public class SendMessages
{
private static readonly string GoogleSheetsCsvUrl = "ENTER_GOOGLE_SHEETS_CSV_URL_HERE"; // Replace with the Google Sheets CSV URL
private static readonly string Token = "API_KEY_GOES_HERE"; // Replace with your Wassenger API Token
private static readonly string DeviceId = "DEVICE_ID"; // Replace with your Device ID
private static readonly string MessagesUrl = "https://api.wassenger.com/v1/messages";
public static async Task RunAsync()
{
var records = await DownloadAndParseCsvAsync(GoogleSheetsCsvUrl);
if (records == null)
{
Console.WriteLine("Failed to process the CSV file.");
return;
}
foreach (var record in records)
{
string phone = record.Phone;
string message = record.Message;
if (string.IsNullOrWhiteSpace(phone) || string.IsNullOrWhiteSpace(message))
{
continue;
}
string normalizedPhone = NormalizePhone(phone);
if (!string.IsNullOrEmpty(normalizedPhone))
{
await SendMessageAsync(normalizedPhone, message);
}
}
}
private static async Task<IEnumerable<Record>> DownloadAndParseCsvAsync(string url)
{
using var httpClient = new HttpClient();
try
{
string csvContent = await httpClient.GetStringAsync(url);
using var reader = new StringReader(csvContent);
using var csv = new CsvReader(reader, CultureInfo.InvariantCulture);
return csv.GetRecords<Record>().ToList();
}
catch (Exception ex)
{
Console.WriteLine($"Error downloading or parsing CSV: {ex.Message}");
return null;
}
}
private static async Task SendMessageAsync(string phone, string message)
{
var client = new RestClient(MessagesUrl);
var request = new RestRequest(Method.POST)
.AddHeader("Authorization", $"Bearer {Token}")
.AddHeader("Content-Type", "application/json")
.AddJsonBody(new
{
phone = phone,
body = message,
device = DeviceId
});
var response = await client.ExecuteAsync(request);
if (response.IsSuccessful)
{
Console.WriteLine($"Message sent to {phone}");
}
else
{
Console.WriteLine($"Failed to send message to {phone}: {response.Content}");
}
}
private static string NormalizePhone(string phone)
{
return "+" + new string(phone.Where(char.IsDigit).ToArray());
}
public class Record
{
[JsonPropertyName("phone")]
public string Phone { get; set; }
[JsonPropertyName("message")]
public string Message { get; set; }
}
}
Play and run code in the cloud without installing any software in your computer. Create a free account in Replit and get started in minutes
Send media messages
In this example, we will create a different program sendMedia.cs
to send multiple image media messages to different phone numbers loaded from a Google Sheets document.
To send a media message, the easiest way is to provide a file download URL. If your file is not already uploaded somewhere, you can upload the file to Google Drive and make the file publicly available to be downloaded by the API to send it later.
Example download URL from a public file in Google Drive:
https://drive.google.com/uc?id=1RG3CAPiwiFlFATUlIIwhk0RrbEU4PgVP&export=download
Important: the given download URL must return the file binary content, otherwise it will fail.
Create a new file named sendMedia.cs
in your project directory and add the following code:
using CsvHelper;
using RestSharp;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
public class SendMedia
{
private static readonly string GoogleSheetsCsvUrl = "ENTER_GOOGLE_SHEETS_CSV_URL_HERE"; // Replace with the Google Sheets CSV URL
private static readonly string FileUrl = "https://picsum.photos/seed/picsum/600/500"; // Replace with your media file URL
private static readonly string Token = "API_KEY_GOES_HERE"; // Replace with your Wassenger API Token
private static readonly string DeviceId = "DEVICE_ID"; // Replace with your Device ID
private static readonly string BaseUrl = "https://api.wassenger.com/v1";
private static readonly string MessagesUrl = $"{BaseUrl}/messages";
private static readonly string FilesUrl = $"{BaseUrl}/files";
public static async Task RunAsync()
{
// Download and parse Google Sheets CSV
var records = await DownloadAndParseCsvAsync(GoogleSheetsCsvUrl);
if (records == null)
{
Console.WriteLine("Failed to process the CSV file.");
return;
}
// Upload file to Wassenger
string fileId = await UploadFileAsync(FileUrl);
if (fileId == null)
{
Console.WriteLine("Failed to upload the file.");
return;
}
// Process and send messages
foreach (var record in records)
{
string phone = record.Phone;
string message = record.Message;
if (string.IsNullOrWhiteSpace(phone) || string.IsNullOrWhiteSpace(message))
{
continue;
}
string normalizedPhone = NormalizePhone(phone);
if (!string.IsNullOrEmpty(normalizedPhone) && normalizedPhone.Length >= 8)
{
await SendMessageAsync(normalizedPhone, message, fileId);
}
}
}
private static async Task<IEnumerable<Record>> DownloadAndParseCsvAsync(string url)
{
using var httpClient = new HttpClient();
try
{
string csvContent = await httpClient.GetStringAsync(url);
using var reader = new StringReader(csvContent);
using var csv = new CsvReader(reader, CultureInfo.InvariantCulture);
return csv.GetRecords<Record>().ToList();
}
catch (Exception ex)
{
Console.WriteLine($"Error downloading or parsing CSV: {ex.Message}");
return null;
}
}
private static async Task<string> UploadFileAsync(string fileUrl)
{
var client = new RestClient(FilesUrl);
var request = new RestRequest(Method.POST)
.AddHeader("Authorization", $"Bearer {Token}")
.AddHeader("Content-Type", "application/json")
.AddJsonBody(new { url = fileUrl });
var response = await client.ExecuteAsync(request);
if (response.IsSuccessful)
{
var responseBody = JsonSerializer.Deserialize<UploadFileResponse>(response.Content);
return responseBody?.Id;
}
else
{
Console.WriteLine($"Failed to upload file: {response.Content}");
return null;
}
}
private static async Task SendMessageAsync(string phone, string message, string fileId)
{
var client = new RestClient(MessagesUrl);
var request = new RestRequest(Method.POST)
.AddHeader("Authorization", $"Bearer {Token}")
.AddHeader("Content-Type", "application/json")
.AddJsonBody(new
{
phone = phone,
message = message.Trim(),
device = DeviceId,
media = new { file = fileId }
});
var response = await client.ExecuteAsync(request);
if (response.IsSuccessful)
{
Console.WriteLine($"Message sent to {phone}");
}
else
{
Console.WriteLine($"Failed to send message to {phone}: {response.Content}");
}
}
private static string NormalizePhone(string phone)
{
return "+" + new string(phone.Where(char.IsDigit).ToArray());
}
public class Record
{
[JsonPropertyName("phone")]
public string Phone { get; set; }
[JsonPropertyName("message")]
public string Message { get; set; }
}
public class UploadFileResponse
{
[JsonPropertyName("id")]
public string Id { get; set; }
}
}
Play and run code in the cloud without installing any software in your computer. Create a free account in Replit and get started in minutes
Replace the Google Sheets URL to export as CSV
In the sendMessages.cs
and sendMedia.cs
files, make sure you have replaced the Google Sheets CSV URL and your actual Wassenger API token:
// Replace this with the URL of your published Google Sheets CSV file
private static readonly string GoogleSheetsCsvUrl = "ENTER_GOOGLE_SHEETS_CSV_URL_HERE";
See the indications above to obtain the Google Sheets download URL to enter here.
Replace the API token
In the send_messages.php
file, make sure you have defined the API token of your actual Wassenger account:
// Replace this with your Wassenger API token
private static readonly string Token = "ENTER API KEY HERE";
Optionally, if you have multiple WhatsApp numbers connected in your Wassenger account, you can specify which WhatsApp number you want to use for the message delivery by specifying the Wassenger unique device ID (24 characters hexadecimal value) in the following line:
// Optionally specify the target WhatsApp device ID connected to Wassenger
private static readonly string DeviceId = "DEVICE ID GOES HERE";
Run the program
Before running the program, if you plan to send hundreds of messages in a row, we recommend defining a lower message delivery speed per minute no more than 2–3 messages to prevent ban issues due to anti-spam policies by WhatsApp. Learn more about best practices and how to reduce risk here.
Run the program in the cloud
You can run the program in the cloud for free on Replit.com without installing any software on your computer.
Simply create a new project and copy & paste the provided code, then click on “Run” to send the messages. It is that simple 😀
Run the program on your computer
Open a terminal in your project directory and run the following command to execute the sendMessages.cs
or sendMedia.cs
script:
dotnet run --project sendMessages.csproj
Similarly, you can run the sendMedia.cs
script to send media messages:
dotnet run --project sendMedia.csproj
If everything is set up correctly, you should see output indicating the messages have been created successfully:
Message sent to +1234567890
Message sent to +1234567890
Message sent to +1234567890
Note messages will be added to your number’s message delivery queue and delivered asynchronously in the background over time based on your number’s subscription message delivery speed per minute limit or the manually configured delivery speed you have defined in your number’s settings.
Messages may take several minutes or hours, depending on how much you have created, to be effectively delivered to the target phone numbers via WhatsApp. You can monitor the progress of the message delivery in the web panel or automatically by using webhook events.
FAQ
How can I obtain the Google Sheets CSV download URL for use with the C#.NET program?
Detailed steps on publishing a Google Sheets document as a CSV are covered, including how to share the file publicly:
- Open your Google Sheets document.
- Go to File > Share > Publish to the web.
- Under the “Link” tab, select Comma-separated values (.csv) as the format.
- Copy the generated link and paste it into the
GoogleSheetsCsvUrl
variable in your C#.NET script.
What prerequisites are needed to send WhatsApp messages from Google Sheets using C#.NET?
To run the C#.NET program, you need:
- .NET SDK installed: Install the latest .NET SDK from Microsoft’s .NET site.
- Required NuGet packages:
- CsvHelper
: For parsing CSV files.
- RestSharp
: For handling HTTP requests to the Wassenger API.
- Wassenger API token: Obtain your API token from the Wassenger dashboard.
- Google Sheets CSV URL: Publish your Google Sheets as a CSV file and copy the download URL.
Run the following commands in the terminal to install the dependencies:
dotnet add package CsvHelper
dotnet add package RestSharp
How can I ensure the messages are delivered without triggering anti-spam policies on WhatsApp?
Best practices for avoiding anti-spam issues include:
- Throttle message delivery: Limit sending to 2–3 messages per minute by introducing a delay between requests:
await Task.Delay(30000); // Adds a 30-second delay
- Personalize messages: Use slight variations in messages to avoid detection as spam.
- Follow WhatsApp’s guidelines: Avoid sending unsolicited messages or excessively repeated content.
- Monitor API responses: Check for errors or rate-limiting messages in the Wassenger API responses to adjust your program accordingly.
For more detailed guidance, refer to Wassenger’s documentation on best practices and anti-spam policies.