Gesgocom.GesSms 1.1.1

GesSms

Cliente .NET 10 tipado y asíncrono para la API SMS JSON de LabsMobile. Incluye envío individual y masivo, programación, saldo, precios, gestión de programados, modelos de callbacks y utilidades GSM-7/Unicode.

Requisitos e instalación

  • .NET 10 (LTS).
  • Una cuenta LabsMobile y un token creado en Configuración API.

El paquete se distribuye en el NuGet privado de Gesgocom. Registra el origen una vez por máquina y añade la referencia:

dotnet nuget add source https://nuget.gesgocom.es/v3/index.json -n Gesgocom
dotnet add package Gesgocom.GesSms

Configuración

using GesSms.Extensions;

builder.Services.AddLabsMobileSms(options =>
{
    options.Username = builder.Configuration["LabsMobile:Username"]!;
    options.ApiToken = builder.Configuration["LabsMobile:ApiToken"]!;
    options.DefaultSenderId = "MiEmpresa";
    options.TimeoutSeconds = 30;
    options.TestMode = false;
});

También se puede enlazar directamente una sección:

{
  "LabsMobile": {
    "Username": "usuario",
    "ApiToken": "token-api",
    "DefaultSenderId": "MiEmpresa",
    "TimeoutSeconds": 30,
    "AutoConfigureMessageParameters": true
  }
}
builder.Services.AddLabsMobileSms(
    builder.Configuration.GetSection("LabsMobile"));

No guardes el token en el repositorio. En producción utiliza secretos de usuario, variables de entorno o un almacén de secretos. BaseUrl debe ser una URL HTTPS y por defecto es https://api.labsmobile.com/json/. El registro mediante AddLabsMobileSms valida credenciales, URL y timeout al arrancar la aplicación para detectar una configuración incompleta antes del primer envío.

Enviar mensajes

using GesSms.Interfaces;

public sealed class Avisos(ILabsMobileSmsService sms)
{
    public async Task EnviarAsync(CancellationToken cancellationToken)
    {
        var result = await sms.SendAsync(
            "34600111222",
            "Tu pedido está preparado.",
            ct: cancellationToken);

        if (!result.IsSuccess)
        {
            // LabsMobile puede comunicar un error funcional en code/message.
        }
    }
}

Para varios destinatarios:

await sms.SendBulkAsync(
    ["34600111222", "34600333444"],
    "Mantenimiento programado a las 22:00",
    senderId: "MiEmpresa",
    ct: cancellationToken);

La librería activa automáticamente long=1 si el texto necesita más de un segmento y ucs2=1 si contiene caracteres fuera de GSM-7. Se puede desactivar con AutoConfigureMessageParameters = false.

Petición avanzada

using GesSms.Models;

var result = await sms.SendAsync(new SendSmsRequest
{
    Recipients = [new Recipient("34600111222")],
    Message = "Hola %name%, consulta https://example.com/pedido/42",
    SenderId = "MiEmpresa",
    SubId = "pedido-42",
    Label = "origen=erp;campaña=estado",
    AckUrl = "https://miapp.example/webhooks/labsmobile/estado",
    ClickUrl = "https://miapp.example/webhooks/labsmobile/clic",
    ShortLink = "1",
    Parameters =
    [
        new Dictionary<string, MessageParameterValue>
        {
            ["name"] = new() { Msisdn = "34600111222", Value = "Ana" }
        }
    ]
}, cancellationToken);

SendSmsRequest también expone Test, Long, Ucs2, NoFilter y los campos de SMS certificado (CertificateEmail, CertificateName, CertificateId y CertificateLanguage). Los indicadores LabsMobile usan los valores de cadena "0" y "1" para conservar compatibilidad con la API.

Envíos de prueba y programados

await sms.SendTestAsync("34600111222", "Prueba", ct: cancellationToken);

await sms.ScheduleAsync(
    "34600111222",
    "Recordatorio de cita",
    DateTimeOffset.UtcNow.AddHours(1),
    ct: cancellationToken);

LabsMobile exige la fecha programada en GMT. La sobrecarga con DateTimeOffset la convierte a UTC; si se usa un DateTime sin Kind, GesSms lo interpreta como UTC. LabsMobile no permite combinar scheduled y test=1, por lo que la librería rechaza esa combinación antes de llamar a la API.

await sms.CancelScheduledAsync("subid", cancellationToken);
await sms.CancelAllScheduledAsync(cancellationToken);
await sms.SendScheduledNowAsync("subid", cancellationToken);
await sms.SendAllScheduledNowAsync(cancellationToken);

Saldo y precios

var balance = await sms.GetBalanceAsync(cancellationToken);
decimal credits = balance.CreditsDecimal;

var spain = await sms.GetPriceAsync("ES", cancellationToken);
var selected = await sms.GetPricesAsync(["ES", "FR"], cancellationToken);
var all = await sms.GetAllPricesAsync(cancellationToken);

Los códigos de país son ISO 3166-1 alfa-2. Una lista vacía consulta todos los países, tal como define LabsMobile.

Errores, cancelación y resiliencia

  • Los errores HTTP, de red, timeout y formato lanzan LabsMobileApiException. La excepción incluye StatusCode, ErrorCode, Operation y un ResponseBody limitado.
  • Una cancelación solicitada por el consumidor conserva OperationCanceledException; no se transforma en un error de LabsMobile.
  • Una respuesta válida de envío o programados con code != "0" se devuelve al llamador y tiene IsSuccess == false.
  • El circuit breaker y los timeouts están activos. Los reintentos se aplican únicamente a métodos HTTP seguros; POST /send nunca se repite para evitar SMS duplicados.
try
{
    await sms.GetBalanceAsync(cancellationToken);
}
catch (LabsMobileApiException ex)
{
    // Registra una sola vez, en el límite de la aplicación donde se decide
    // que el fallo no puede recuperarse o necesita contexto de negocio.
    logger.LogError(ex,
        "LabsMobile falló en {Operation}; HTTP {Status}; código {Code}",
        ex.Operation, ex.StatusCode, ex.ErrorCode);
}

GesSms no escribe estos fallos como Error antes de propagarlos: únicamente emite un diagnóstico interno en Debug. Así se evita duplicar el evento cuando la aplicación registra la excepción. Los rechazos funcionales que LabsMobile devuelve sin lanzar una excepción se registran como Warning.

Logs y observabilidad

GesSms utiliza exclusivamente Microsoft.Extensions.Logging. No instala ni configura proveedores: los eventos se envían automáticamente a los proveedores de la aplicación, como consola, Serilog, NLog, Application Insights u OpenTelemetry. La categoría es GesSms.Services.LabsMobileSmsService y se puede filtrar mediante el prefijo GesSms.

Configuración recomendada para producción:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "GesSms": "Warning",
      "System.Net.Http.HttpClient": "Warning"
    }
  }
}

Para diagnosticar temporalmente una integración, cambia GesSms a Debug. Esto añade el inicio y resultado de cada operación, junto con el detalle técnico de excepciones que después se entregan al consumidor. Cada petición crea además un scope estructurado con LabsMobileOperation (send, balance, prices o scheduled), que los proveedores con soporte de scopes pueden correlacionar con el resto de logs de la aplicación.

EventId EventName Nivel Significado
1000 ServiceNotConfigured Warning Cliente construido manualmente sin credenciales.
1100 SendStarted Debug Inicio de un envío; solo incluye la cantidad de destinatarios.
1101 SendSucceeded Debug Envío aceptado y SubId recibido.
1102 SendRejected Warning Rechazo funcional devuelto en code/message.
1200 HttpRequestFailed Debug Respuesta HTTP no satisfactoria que se propagará como excepción.
1201 ResponseDeserializationFailed Debug Respuesta no compatible con el contrato esperado.
1202 ConnectionFailed Debug Fallo de transporte o conexión.
1203 RequestTimedOut Debug Timeout del cliente o de la política de resiliencia.
1300–1302 Balance* Debug/Warning Inicio, éxito o rechazo de saldo.
1400–1401 Prices* Debug Inicio y éxito de precios.
1500–1502 ScheduledCommand* Debug/Warning Gestión de programados.

La librería nunca registra el token, el texto del mensaje ni los teléfonos de los destinatarios. Sí puede registrar SubId, códigos del proveedor, número de destinatarios y saldo en nivel Debug. No incluyas datos personales o secretos en SubId y revisa las políticas de retención del proveedor de logs.

No registres y vuelvas a lanzar la misma excepción en todas las capas. Regístrala una vez en el límite que conoce el resultado final de la operación. Si una capa puede recuperarse, reintentar deliberadamente o transformar el fallo, puede no ser necesario escribir un evento de error.

Utilidades SMS

ISmsUtils permite detectar GSM-7/Unicode, calcular segmentos, truncar sin separar pares sustitutos (emoji), sustituir caracteres, estimar créditos y hacer una validación sintáctica de teléfonos E.164. No sustituye a una validación HLR ni confirma que un número exista.

var info = smsUtils.AnalyzeMessage("Hola €");
// info.Encoding, info.SegmentCount, info.RemainingChars...

Se puede registrar de forma independiente con services.AddSmsUtils().

Callbacks

Se incluyen DeliveryStatusCallback, ClickTrackingCallback e InboundMessageCallback. El estado de entrega llega por HTTP GET (query string); clics y mensajes entrantes llegan por HTTP POST JSON. Tu endpoint debe devolver un estado 2xx: LabsMobile reintenta callbacks fallidos.

Consulta los campos, ejemplos ASP.NET Core, códigos y restricciones en docs/LabsMobile.md.

Fuentes oficiales

La documentación se contrastó con las fuentes oficiales el 5 de agosto de 2026.

Licencia

MIT. Consulta LICENSE.

No packages depend on Gesgocom.GesSms.

Actualización a .NET 10 y dependencias vigentes, validación de configuración al inicio, resiliencia segura para POST, eventos de log estructurados sin doble registro, soporte completo de parámetros JSON de LabsMobile y documentación de integración.

Version Downloads Last updated
1.1.2 46 08/07/2026
1.1.1 8 08/06/2026
1.1.0 8 08/05/2026