Hola, chicos,
¡Buen día!

En esta publicación, demostraré cómo enviar SMS Torpedoes usando CLR (C#) y Mais Resultado (PG Soluções) API a través de la base de datos de SQL Server. Esto es especialmente útil cuando necesita crear alertas y monitorear sus rutinas críticas, que operan tarde en la noche o los fines de semana y requieren una acción inmediata.

¿Por qué utilizar esta API? ¿Y la solución con Pushbullet?

ya habia hecho la publicacion Cómo utilizar la API Pushbullet para enviar mensajes de texto SMS en C#, PHP, Java o SQL Server (con CLR), que permitía el envío de mensajes de texto SMS a través de la base de datos SQL Server utilizando la API Pushbullet y un teléfono celular físico para realizar el envío, pero a pesar de ser un método mucho más económico (utilizará los mensajes de texto “ilimitados” de tu chip), existe la necesidad de tener un teléfono siempre encendido y conectado a Internet.

Además, sabemos que los mensajes de texto “ilimitados” de los operadores de telefonía móvil nunca son realmente ILIMITADOS, porque pretendiendo evitar el spam, crean una serie de limitaciones en la cantidad mensual de SMS. Algunos operadores los limitan a unos 10.000 mensajes de texto SMS (en el mejor de los casos y si no cancelan su contrato), otros exigen que el número de mensajes de texto enviados sea como máximo de 2.500 mensajes de texto/mes y como máximo el doble de los recibidos, etc.

Como necesitaba una solución que me permitiera enviar más de 10.000 mensajes de texto al mes, esta solución no cumplía esa necesidad. Incluso se podrían comprar varios chips y teléfonos móviles y crear un “grupo de teléfonos móviles”, pero dependiendo de la importancia de la información, puede que no valga la pena correr el riesgo.

Ante esta necesidad, les presento el Soluciones PG, una empresa de Paraná especializada en el envío de mensajes de texto SMS masivos, que proporciona una API para la integración con otros lenguajes de programación y así permitir el envío automatizado. El coste de los SMS es relativamente bajo (si no me equivoco, cuesta 5 céntimos por mensaje de texto, pero el importe puede variar según la negociación).

PD: Para que quede claro, no soy parte de la empresa ni conozco a nadie allí. Sólo estoy demostrando esta solución porque fue la que me pareció más viable para enviar los SMS que uso en la empresa donde trabajo.

Una vez que ya hayas completado tu contrato con PG, podrás acceder a la área administrativa, donde podrás visualizar los mensajes de texto enviados por la API y gestionar el registro de clientes (En la API puedes crear varios clientes, que pueden ser sectores de tu empresa o diferentes clientes).

Cómo enviar mensajes de texto SMS usando la API Mais Resultado

Ahora que está familiarizado con la herramienta y ya tiene contrato con PG Soluções, puede comenzar a enviar sus mensajes de texto SMS a través de su sistema C# o a través de su base de datos SQL Server utilizando el CLR (C#).

Antes de comenzar, es necesario tener a mano el token de autenticación proporcionado por PG. Este token es lo que le permite identificar los mensajes de texto enviados por usted como sus mensajes de texto y, por lo tanto, nunca revele ni comparta este token.

Como requisito previo para utilizar este procedimiento, deberá crear la clase Devolución, disponible en la publicación SQL Server: cómo enviar advertencias y mensajes de error a la base de datos usando CLR (C#) para usar el método Devolución.Error y así, enviar mensajes de error, si se producen. También puedes optar por comentar el código y eliminar llamadas a este método (y también comentar usando Bibliotecas.Model), pero no lo recomiendo, ya que no sabrás cuándo ocurrió un error en tu llamada al SP de envío de mensajes de texto SMS.

Código fuente del procedimiento:

using System;
using System.Data;
using System.Data.SqlTypes;
using System.IO;
using System.Net;
using System.Text;
using System.Xml;
using Bibliotecas.Model;
using Microsoft.SqlServer.Server;

public partial class StoredProcedures
{
    [Microsoft.SqlServer.Server.SqlProcedure]
    public static void stpEnvia_Torpedo_PG(SqlString Nr_Numero, SqlString Ds_Mensagem, SqlDateTime Dt_Agendamento, SqlString Cd_Cliente)
    {


        var token = "meu_token";

        if (Nr_Numero.Value.Length <= 9)
            Retorno.Erro("Favor informar o número de telefone com DDD");

        if (Ds_Mensagem.Value.Length > 160)
            Retorno.Erro("O tamanho máximo da mensagem a ser enviada por SMS é de 160 caracteres");

        
        try
        {

            
            var request = (HttpWebRequest) WebRequest.Create("http://api.recuperemais.com.br/send");
            
            request.Method = "POST";
            request.UserAgent = "curl/7.45.0";
            request.ContentType = "application/x-www-form-urlencoded";

            var parametros = $"token={token}&sms_to={Nr_Numero.Value}&sms_msg={Ds_Mensagem.Value}&sms_cliente={Cd_Cliente.Value}" + ((!Dt_Agendamento.IsNull) ? "&sms_data=" + Dt_Agendamento.Value.ToString("yyyy-MM-dd hh:mm:ss") : "");

            var buffer = Encoding.GetEncoding("UTF-8").GetBytes(parametros);
            using (var reqstr = request.GetRequestStream())
            {
                reqstr.Write(buffer, 0, buffer.Length);

                using (var response = request.GetResponse())
                {

                    using (var dataStream = response.GetResponseStream())
                    {

                        if (dataStream == null) return;

                        using (var reader = new StreamReader(dataStream))
                        {

                            var responseFromServer = reader.ReadToEnd();

                            var xml = new XmlDocument();
                            xml.LoadXml(responseFromServer);

                            var retorno = xml.SelectSingleNode("//pgdigitalsms")?.FirstChild.Attributes?["id"].Value;
                            if (retorno == null)
                            {
                                Retorno.Erro("Erro desconhecido ao recuperar o id retornado");
                                return;
                            }

                            var codigoRetorno = int.Parse(retorno);


                            if (codigoRetorno > 5)
                            {

                                var pipe = SqlContext.Pipe;
                                
                                var colunas = new SqlMetaData[3];
                                colunas[0] = new SqlMetaData("Ds_Numero", SqlDbType.VarChar, 50);
                                colunas[1] = new SqlMetaData("Nr_Retorno", SqlDbType.BigInt);
                                colunas[2] = new SqlMetaData("Ds_Mensagem", SqlDbType.VarChar, 4000);

                                var linhaSql = new SqlDataRecord(colunas);
                                
                                if (pipe == null) return;

                                pipe.SendResultsStart(linhaSql);
                                
                                linhaSql.SetSqlString(0, new SqlString(Nr_Numero.Value));
                                linhaSql.SetSqlInt64(1, new SqlInt64(codigoRetorno));
                                linhaSql.SetSqlString(2, new SqlString("Torpedo enviado com sucesso"));

                                pipe.SendResultsRow(linhaSql);
                                pipe.SendResultsEnd();

                            }
                            else
                            {

                                string msgErro;

                                switch (codigoRetorno)
                                {
                                    case 1:
                                    {
                                        msgErro = "Erro de autenticação de sua conta PG SMS";
                                        break;
                                    }

                                    case 2:
                                    {
                                        msgErro = "Erro nos parâmetros informados";
                                        break;
                                    }

                                    case 3:
                                    {
                                        msgErro = "Registros não encontrados";
                                        break;
                                    }

                                    case 4:
                                    {
                                        msgErro = "Mensagem não encontrada no banco de dados";
                                        break;
                                    }

                                    case 5:
                                    default:
                                    {
                                        msgErro = "Telefone Inválido";
                                        break;
                                    }
                                }


                                var pipe = SqlContext.Pipe;

                                var colunas = new SqlMetaData[3];
                                colunas[0] = new SqlMetaData("Ds_Numero", SqlDbType.VarChar, 50);
                                colunas[1] = new SqlMetaData("Nr_Retorno", SqlDbType.BigInt);
                                colunas[2] = new SqlMetaData("Ds_Mensagem", SqlDbType.VarChar, 4000);

                                var linhaSql = new SqlDataRecord(colunas);

                                if (pipe == null) return;

                                pipe.SendResultsStart(linhaSql);

                                linhaSql.SetSqlString(0, new SqlString(Nr_Numero.Value));
                                linhaSql.SetSqlInt64(1, new SqlInt64(codigoRetorno));
                                linhaSql.SetSqlString(2, new SqlString(msgErro));

                                pipe.SendResultsRow(linhaSql);
                                pipe.SendResultsEnd();


                                Retorno.Erro(msgErro);

                            }

                        }
                    }

                }

            }

        }
        catch (Exception e)
        {
            Retorno.Erro("Erro : " + e.Message + "\n\nInner exception: " + e.InnerException);
        }

    }

};

Ejemplos de uso:

-- Enviar torpedo agora
EXEC CLR.dbo.stpEnvia_Torpedo_PG 
    @Nr_Numero = N'27111111111', -- nvarchar(max)
    @Ds_Mensagem = N'Teste', -- nvarchar(max)
    @Dt_Agendamento = NULL, -- datetime
    @Cd_Cliente = N'Dirceu_Resende' -- nvarchar(max)


-- Enviar torpedo no meu aniversário
EXEC CLR.dbo.stpEnvia_Torpedo_PG 
    @Nr_Numero = N'27111111111', -- nvarchar(max)
    @Ds_Mensagem = N'Teste', -- nvarchar(max)
    @Dt_Agendamento = '2017-05-28 08:00:00', -- datetime
    @Cd_Cliente = N'Dirceu_Resende' -- nvarchar(max)

Automatizando el envío de torpedos

Un consejo que puede utilizar, que yo uso a diario, es crear una tabla de torpedos, de modo que sus rutinas simplemente inserten los datos de los torpedos en esta tabla y creen un trabajo que lea los torpedos no enviados de esta tabla y dispare los torpedos usando el CLR.

Creando la tabla base:

CREATE TABLE dbo.Torpedo (
    Id_Torpedo INT NOT NULL IDENTITY(1, 1),
    Nr_Telefone varchar (11) NOT NULL,
    Ds_Mensagem varchar (200) NOT NULL,
    Dt_Cadastro datetime NOT NULL CONSTRAINT DF_Torpedo_Dt_Cadastro DEFAULT (getdate())
) WITH(DATA_COMPRESSION = PAGE)
GO

Procedimiento almacenado para realizar envío automatizado:

CREATE PROCEDURE [dbo].[stpRotina_Envia_Torpedo]
AS
BEGIN 

    IF (OBJECT_ID('dbo.Torpedos_Enviados') IS NULL)
    BEGIN
    
        CREATE TABLE dbo.Torpedos_Enviados (
            Id_Torpedo INT NOT NULL,
            Cd_Envio bigint
        ) WITH(DATA_COMPRESSION = PAGE)

    END


    IF (OBJECT_ID('tempdb..#Fila') IS NOT NULL) DROP TABLE #Fila
    SELECT 
        IDENTITY(INT, 1, 1) AS Ranking,
        A.Id_Torpedo,
        A.Nr_Telefone,
        A.Ds_Mensagem,
        A.Dt_Cadastro
    INTO 
        #Fila
    FROM 
        dbo.Torpedo			        A	WITH(NOLOCK)
        LEFT JOIN dbo.Torpedos_Enviados		B	WITH(NOLOCK) ON A.Id_Torpedo = B.Id_Torpedo
    WHERE 
        A.Dt_Cadastro >= DATEADD(MINUTE, -10, GETDATE())
        AND B.Id_Torpedo IS NULL


    IF (OBJECT_ID('tempdb..#Retorno') IS NOT NULL) DROP TABLE #Retorno
    CREATE TABLE #Retorno (
        Ds_Numero VARCHAR(50),
        Nr_Retorno BIGINT,
        Ds_Mensagem VARCHAR(MAX)
    )


    DECLARE
        @Contador INT = 1,
        @Total INT = (SELECT COUNT(*) FROM #Fila),
        @Nr_Telefone VARCHAR(30),
        @Ds_Mensagem VARCHAR(160),
        @Id_Torpedo INT,
        @Cd_Retorno_PG BIGINT


    WHILE(@Contador <= @Total)
    BEGIN


        SELECT
            @Id_Torpedo = Id_Torpedo,
            @Ds_Mensagem = REPLACE(Ds_Mensagem, '\', '/'),
            @Nr_Telefone = Nr_Telefone
        FROM
            #Fila
        WHERE
            Ranking = @Contador

    
        BEGIN TRY
            

            TRUNCATE TABLE #Retorno
            

            INSERT INTO #Retorno
            EXEC CLR.dbo.stpEnvia_Torpedo_PG
                @Nr_Numero = @Nr_Telefone, -- nvarchar(max)
                @Ds_Mensagem = @Ds_Mensagem, -- nvarchar(max)
                @Dt_Agendamento = NULL,
                @Cd_Cliente = 'Nome_Do_Cliente'


            SELECT TOP 1 @Cd_Retorno_PG = Nr_Retorno
            FROM #Retorno

            
            INSERT INTO dbo.[Torpedos_Enviados]
            VALUES(@Id_Torpedo, @Cd_Retorno_PG)


        END TRY
        BEGIN CATCH
            RAISERROR('Erro ao enviar SMS', 16, 1)
        END CATCH
    

        SET @Contador = @Contador + 1

    END

END

Ahora solo necesitas crear un Trabajo en el Agente SQL de tu instancia para ejecutar el stpRotina_Send_Torpedo creado arriba. Normalmente configuro el trabajo para que se ejecute cada minuto, pero depende de usted y de sus necesidades.

¡Y eso es todo, amigos!
Espero que te haya gustado esta publicación.
Un abrazo y hasta la próxima.

servidor sql clr .net dotnet framework c# integración csharp cómo crear base de datos integración base de datos cómo enviar mensajes cómo enviar mensajes notificaciones mensajes de texto sms

servidor sql clr .net dotnet framework c# integración csharp cómo crear base de datos integración base de datos cómo enviar mensajes cómo enviar mensajes notificaciones mensajes de texto sms