Passa al contenuto principale

SMS in entrata

Cos'è l'SMS in entrata

Noleggia un numero di telefono dedicato per ricevere tutti gli SMS in arrivo in tempo reale. Agile Telecom ospita la SIM e inoltra i messaggi tramite email o webhook -- ideale per linee di assistenza clienti, promemoria appuntamenti o risposte automatiche.


Consegna tramite email

Quando la consegna tramite email è configurata, gli SMS in arrivo vengono inoltrati al tuo indirizzo email specificato da smsin@agiletelecom.com.

Ogni email contiene i seguenti campi:

CampoDescrizione
FromNumero di telefono del mittente (MSISDN)
ToIl tuo numero dedicato
Date/TimeTimestamp di ricezione del messaggio
BodyContenuto testuale dell'SMS

:::tip Configurazione semplice La consegna tramite email non richiede sviluppo -- basta configurare il tuo indirizzo email di destinazione nel portale e iniziare a ricevere i messaggi immediatamente. :::


Webhook HTTP POST

Per l'elaborazione programmatica, configura un webhook HTTP POST. Agile Telecom invierà i dati degli SMS in arrivo al tuo endpoint.

Parametri della richiesta

ParametroTipoDescrizione
originatorstringNumero di telefono del mittente (MSISDN)
destinationstringIl tuo numero dedicato
date_timestringTimestamp di ricezione del messaggio
textstringContenuto testuale dell'SMS

Requisiti della risposta

Il tuo endpoint deve rispondere con +OK nel corpo della risposta. Qualsiasi altra risposta viene considerata un errore.

ImpostazioneValore
Risposta richiesta+OK
Timeout30 secondi
Ritardo tra i tentativi15 minuti
Tentativi massimi3

:::warning Risposta obbligatoria Se il tuo endpoint non risponde con +OK entro 30 secondi, il sistema effettuerà fino a 3 tentativi con un intervallo di 15 minuti tra un tentativo e l'altro. Dopo 3 fallimenti, il messaggio viene scartato. :::


Esempi di implementazione del webhook

Python (Flask)

from flask import Flask, request
import threading

app = Flask(__name__)

def process_message(originator, destination, date_time, text):
"""Process inbound SMS asynchronously."""
print(f"From: {originator}, To: {destination}, Time: {date_time}")
print(f"Message: {text}")
# Add your business logic here

@app.route("/inbound-sms", methods=["POST"])
def inbound_sms():
originator = request.form.get("originator")
destination = request.form.get("destination")
date_time = request.form.get("date_time")
text = request.form.get("text")

# Process asynchronously to respond fast
thread = threading.Thread(
target=process_message,
args=(originator, destination, date_time, text)
)
thread.start()

return "+OK"

if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000)

Node.js (Express)

const express = require("express");
const app = express();

app.use(express.urlencoded({ extended: true }));

function processMessage(originator, destination, dateTime, text) {
console.log(`From: ${originator}, To: ${destination}, Time: ${dateTime}`);
console.log(`Message: ${text}`);
// Add your business logic here
}

app.post("/inbound-sms", (req, res) => {
const { originator, destination, date_time, text } = req.body;

// Process asynchronously to respond fast
setImmediate(() => processMessage(originator, destination, date_time, text));

res.send("+OK");
});

app.listen(3000, () => console.log("Listening on port 3000"));

PHP

<?php
// inbound-sms.php

$originator = $_POST['originator'] ?? '';
$destination = $_POST['destination'] ?? '';
$date_time = $_POST['date_time'] ?? '';
$text = $_POST['text'] ?? '';

// Log the message
$logEntry = sprintf(
"[%s] From: %s, To: %s, Message: %s\n",
$date_time, $originator, $destination, $text
);
file_put_contents('inbound-sms.log', $logEntry, FILE_APPEND);

// Process your business logic here
// ...

// Required response
echo "+OK";

Java (Spring Boot)

import org.springframework.web.bind.annotation.*;
import java.util.concurrent.CompletableFuture;

@RestController
public class InboundSmsController {

@PostMapping("/inbound-sms")
public String handleInboundSms(
@RequestParam String originator,
@RequestParam String destination,
@RequestParam("date_time") String dateTime,
@RequestParam String text) {

// Process asynchronously
CompletableFuture.runAsync(() -> {
System.out.printf("From: %s, To: %s, Time: %s%n", originator, destination, dateTime);
System.out.printf("Message: %s%n", text);
// Add your business logic here
});

return "+OK";
}
}

Go (net/http)

package main

import (
"fmt"
"net/http"
)

func processMessage(originator, destination, dateTime, text string) {
fmt.Printf("From: %s, To: %s, Time: %s\n", originator, destination, dateTime)
fmt.Printf("Message: %s\n", text)
// Add your business logic here
}

func inboundSmsHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}

r.ParseForm()
originator := r.FormValue("originator")
destination := r.FormValue("destination")
dateTime := r.FormValue("date_time")
text := r.FormValue("text")

// Process asynchronously
go processMessage(originator, destination, dateTime, text)

fmt.Fprint(w, "+OK")
}

func main() {
http.HandleFunc("/inbound-sms", inboundSmsHandler)
fmt.Println("Listening on :8080")
http.ListenAndServe(":8080", nil)
}

C# (ASP.NET)

using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("inbound-sms")]
public class InboundSmsController : ControllerBase
{
[HttpPost]
public IActionResult HandleInboundSms(
[FromForm] string originator,
[FromForm] string destination,
[FromForm(Name = "date_time")] string dateTime,
[FromForm] string text)
{
// Process asynchronously
_ = Task.Run(() =>
{
Console.WriteLine($"From: {originator}, To: {destination}, Time: {dateTime}");
Console.WriteLine($"Message: {text}");
// Add your business logic here
});

return Content("+OK");
}
}

Ruby (Sinatra)

require "sinatra"

def process_message(originator, destination, date_time, text)
puts "From: #{originator}, To: #{destination}, Time: #{date_time}"
puts "Message: #{text}"
# Add your business logic here
end

post "/inbound-sms" do
originator = params["originator"]
destination = params["destination"]
date_time = params["date_time"]
text = params["text"]

# Process asynchronously
Thread.new { process_message(originator, destination, date_time, text) }

"+OK"
end

Buone pratiche

Rispondi velocemente

Il tuo endpoint deve restituire +OK entro 1 secondo per evitare problemi di timeout. Delega tutta l'elaborazione a worker in background o thread asincroni.

:::tip Prestazioni Rispondi sempre con +OK prima di elaborare il messaggio. Utilizza pattern asincroni (thread, code, job in background) per la logica di business. :::

Gestisci i duplicati

A causa dei tentativi di reinvio, il tuo webhook potrebbe ricevere lo stesso messaggio più di una volta. Implementa l'idempotenza utilizzando un hash del messaggio:

import hashlib

seen_messages = set()

def is_duplicate(originator, destination, date_time, text):
msg_hash = hashlib.sha256(
f"{originator}{destination}{date_time}{text}".encode()
).hexdigest()

if msg_hash in seen_messages:
return True
seen_messages.add(msg_hash)
return False

:::caution Uso in produzione L'esempio con set() in memoria sopra è solo a scopo illustrativo. In produzione, utilizza un archivio persistente come Redis o un database con scadenza basata su TTL. :::

Registra tutto

Registra ogni messaggio in arrivo con timestamp, mittente e risultato dell'elaborazione. Questo è essenziale per il debug dei problemi di consegna e per l'audit.

Monitora i fallimenti

Configura gli avvisi per:

  • Tempi di risposta del webhook superiori a 5 secondi
  • Tasso di errore superiore all'1%
  • Messaggi mancanti (lacune nelle sequenze attese)