Gesgocom.GesSms 1.1.2
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 incluyeStatusCode,ErrorCode,Operationy unResponseBodylimitado. - 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 tieneIsSuccess == false. - El circuit breaker y los timeouts están activos. Los reintentos se aplican
únicamente a métodos HTTP seguros;
POST /sendnunca 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.
.NET 10.0
- Microsoft.Extensions.Configuration.Abstractions (>= 10.0.10)
- Microsoft.Extensions.Http (>= 10.0.10)
- Microsoft.Extensions.Http.Resilience (>= 10.8.0)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.10)
- Microsoft.Extensions.Options (>= 10.0.10)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 10.0.10)
- Polly.Core (>= 8.7.0)
- Polly.Extensions (>= 8.7.0)
- Polly.RateLimiting (>= 8.7.0)
- System.Threading.RateLimiting (>= 10.0.10)