Enviar mensajes de WhatsApp desde Google Sheets usando C NET

18 de diciembre de 2024

En este tutorial aprenderás a enviar mensajes a números de teléfono almacenados en un archivo CSV de Google Sheets usando C# y Wassenger API. Descargaremos el archivo CSV de Google Sheets, leeremos los números de teléfono y enviaremos mensajes a través de tu número de WhatsApp

Cómo automatizar WhatsApp con IA

Requisitos previos

  • Conocimientos básicos de C# (.NET): Familiaridad con la programación en C# y el manejo de APIs HTTP.
  • .NET instalado: Asegúrate de que el SDK de .NET esté instalado en tu equipo. Puedes descargarlo desde el sitio web de .NET de Microsoft.
  • Paquetes NuGet: Instala las siguientes librerías: - CsvHelper: Para analizar archivos CSV descargados de Google Sheets. - RestSharp: Para realizar solicitudes HTTP a la API de Wassenger.
  • Token de la API de Wassenger: Puedes obtener tu token de API en Wassenger registrándote, creando un workspace y generando una clave de API.
  • URL de descarga CSV de Google Sheets: Publica tu Google Sheets como un archivo CSV y copia la URL de descarga. Esto requiere habilitar “Publicar en la web” en Google Sheets y copiar el enlace.

Instalar paquetes requeridos

Primero, crea un nuevo directorio para tu proyecto y navega a él en tu terminal. Luego, ejecuta los siguientes comandos para instalar las librerías necesarias:

Instalar paquetes requeridos

  1. Crea un nuevo directorio para tu proyecto:
mkdir WhatsAppMessaging cd WhatsAppMessaging
  1. Inicializa un nuevo proyecto .NET:
dotnet new console
  1. Instala los paquetes NuGet necesarios:
  • CsvHelper para leer archivos CSV:
dotnet add package CsvHelper
  • RestSharp para manejar solicitudes HTTP:
dotnet add package RestSharp

Prepara el archivo CSV de Google Sheets

Crea un nuevo documento de Google Sheets y complétalo con dos columnas:

  • Primera columna: número de teléfono en formato E164 con el prefijo del país.
  • Segunda columna: mensaje de texto a enviar al número de destino.

El documento de Google Sheets debería tener al menos dos columnas y verse así:

El documento equivalente exportado como CSV debería verse así:

(+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! 🤗");

Obtén la URL de descarga de tu documento de Google Sheets

  1. Haz clic en “File” en la esquina superior izquierda.
  2. Ve a “Share” > “Publish to the web”.
  3. En la pestaña “Link”, selecciona “Comma-separated values (.csv)” del menú desplegable.
  4. Selecciona la hoja (sheet) deseada con los datos relevantes: por defecto la primera.
  5. Haz clic en “Publish” y copia la URL.

Enviar mensajes de texto

Crea un nuevo archivo llamado sendMessages.cs en el directorio de tu proyecto y añade el siguiente código:

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; }
}

}

Ejecuta y prueba el código en la nube sin instalar software en tu equipo. Crea una cuenta gratuita en Replit y comienza en minutos

Enviar mensajes multimedia

En este ejemplo, crearemos un programa distinto sendMedia.cs para enviar múltiples mensajes multimedia de imagen a diferentes números cargados desde un documento de Google Sheets.

Para enviar un mensaje multimedia, la forma más fácil es proporcionar una URL de descarga del archivo. Si tu archivo no está subido en ningún lugar, puedes subir el archivo a Google Drive y hacer que el archivo sea públicamente accesible para que la API pueda descargarlo y enviarlo más tarde.

Ejemplo de URL de descarga desde un archivo público en Google Drive:

https://drive.google.com/uc?id=1RG3CAPiwiFlFATUlIIwhk0RrbEU4PgVP&export=download

Importante: la URL de descarga proporcionada debe devolver el contenido binario del archivo; de lo contrario fallará.

Crea un nuevo archivo llamado sendMedia.cs en el directorio de tu proyecto y añade el siguiente código:

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; }
}

}

Ejecuta y prueba el código en la nube sin instalar software en tu equipo. Crea una cuenta gratuita en Replit y comienza en minutos

Reemplaza la URL de Google Sheets para exportar como CSV

En los archivos sendMessages.cs y sendMedia.cs, asegúrate de haber reemplazado la URL CSV de Google Sheets y tu token real de la API de Wassenger:

// Replace this with the URL of your published Google Sheets CSV file
private static readonly string GoogleSheetsCsvUrl = "ENTER_GOOGLE_SHEETS_CSV_URL_HERE";

Consulta las indicaciones anteriores para obtener la URL de descarga de Google Sheets que debes colocar aquí.

Reemplaza el token de la API

En el archivo send_messages.php, asegúrate de haber definido el token de la API de tu cuenta real de Wassenger:

// Replace this with your Wassenger API token
private static readonly string Token = "ENTER API KEY HERE";

Opcionalmente, si tienes varios números de WhatsApp conectados en tu cuenta de Wassenger, puedes especificar qué número de WhatsApp quieres usar para la entrega de mensajes indicando el ID único del dispositivo de Wassenger (valor hexadecimal de 24 caracteres) en la siguiente línea:

// Optionally specify the target WhatsApp device ID connected to Wassenger private static readonly string DeviceId = "DEVICE ID GOES HERE";

Ejecutar el programa

Antes de ejecutar el programa, si planeas enviar cientos de mensajes seguidos, recomendamos definir una velocidad de entrega de mensajes más baja por minuto, no más de 2–3 mensajes, para prevenir problemas de baneo debido a las políticas anti-spam de WhatsApp. Más información sobre buenas prácticas y cómo reducir el riesgo aquí.

Ejecutar el programa en la nube

Puedes ejecutar el programa en la nube de forma gratuita en Replit.com sin instalar software en tu equipo.

Simplemente crea un nuevo proyecto y copia & pega el código proporcionado, luego haz clic en “Run” para enviar los mensajes. Es así de sencillo 😀

Ejecutar el programa en tu equipo

Abre una terminal en el directorio de tu proyecto y ejecuta el siguiente comando para ejecutar el script sendMessages.cs o sendMedia.cs:

dotnet run --project sendMessages.csproj

De forma similar, puedes ejecutar el script sendMedia.cs para enviar mensajes multimedia:

dotnet run --project sendMedia.csproj

Si todo está configurado correctamente, deberías ver una salida indicando que los mensajes se han creado correctamente:

Message sent to +1234567890
Message sent to +1234567890
Message sent to +1234567890

Ten en cuenta que los mensajes se añadirán a la cola de entrega de mensajes de tu número y se entregarán de forma asíncrona en segundo plano con el tiempo, según el límite de velocidad de entrega de mensajes por minuto de la suscripción de tu número o la velocidad de entrega configurada manualmente en la configuración de tu número.

Los mensajes pueden tardar varios minutos u horas, dependiendo de la cantidad creada, en ser efectivamente entregados a los números de teléfono destino vía WhatsApp. Puedes monitorear el progreso de la entrega de mensajes en el panel web o automáticamente usando eventos webhook.

Preguntas frecuentes

¿Cómo puedo obtener la URL de descarga CSV de Google Sheets para usar con el programa C#.NET?

Los pasos detallados para publicar un documento de Google Sheets como CSV están cubiertos, incluyendo cómo compartir el archivo públicamente:

  1. Abre tu documento de Google Sheets.
  2. Ve a Archivo > Compartir > Publicar en la web.
  3. En la pestaña “Enlace”, selecciona Comma-separated values (.csv) como formato.
  4. Copia el enlace generado y pégalo en la variable GoogleSheetsCsvUrl en tu script C#.NET.

¿Qué requisitos previos se necesitan para enviar mensajes de WhatsApp desde Google Sheets usando C#.NET?

Para ejecutar el programa C#.NET, necesitas:

- CsvHelper: Para analizar archivos CSV.

- RestSharp: Para manejar solicitudes HTTP a la API de Wassenger.

  • Token de la API de Wassenger: Obtén tu token de API desde el panel de Wassenger.
  • URL CSV de Google Sheets: Publica tu Google Sheets como CSV y copia la URL de descarga.

Ejecuta los siguientes comandos en la terminal para instalar las dependencias:

dotnet add package CsvHelper
dotnet add package RestSharp

¿Cómo puedo asegurar que los mensajes se entreguen sin activar las políticas anti-spam de WhatsApp?

Las mejores prácticas para evitar problemas de spam incluyen:

  • Regular la entrega de mensajes: Limita el envío a 2–3 mensajes por minuto introduciendo una demora entre solicitudes:
await Task.Delay(30000); // Adds a 30-second delay
  • Personalizar los mensajes: Usa variaciones leves en los mensajes para evitar ser detectado como spam.
  • Seguir las directrices de WhatsApp: Evita enviar mensajes no solicitados o contenido excesivamente repetido.
  • Monitorear las respuestas de la API: Revisa errores o mensajes de limitación de tasa en las respuestas de la API de Wassenger para ajustar tu programa según sea necesario.

Para una guía más detallada, consulta la documentación de Wassenger sobre buenas prácticas y políticas anti-spam.

Ready to transform your WhatsApp communication?

Start automating your customer interactions today with Wassenger

Get Started Free