From 5b339fdc0d594ef7dde987a07e55ee5968343873 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 27 Jul 2026 04:01:52 +0000 Subject: [PATCH 1/2] Try qualifying MessageSend's To with a domain -- To/From asymmetry Live test: AMI MessageSend to a bare "pjsip:212" produced zero SIP wire traffic (confirmed via `pjsip set logger on` during a real delivery attempt with the target extension actively registered) -- Asterisk never even tried reaching the registered contact, meaning the failure was in URI resolution before anything got sent, not a rejection from the softphone. From already carried a domain (SMS_DOMAIN); To didn't. Testing whether that asymmetry was the actual cause. Explicitly a live experiment, not a confirmed fix -- next test will show whether this produces real SIP MESSAGE traffic in the logger. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01JDyKC6Kdg7tofmYSmRtgww --- services/sms-inbound.sh | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/services/sms-inbound.sh b/services/sms-inbound.sh index 118d7f3..9c72b9a 100644 --- a/services/sms-inbound.sh +++ b/services/sms-inbound.sh @@ -367,9 +367,16 @@ def ami_deliver(from_number, to_exts, body): from_uri = "".format(from_number or "unknown", SMS_DOMAIN or "localhost") for ext in to_exts: + # A bare "pjsip:{ext}" (no domain) for To, tried first, produced + # zero SIP wire traffic at all -- confirmed live via `pjsip set + # logger on` during a real delivery attempt, so the failure was + # happening at URI resolution inside Asterisk, before it ever + # tried to reach the registered contact. From already carried a + # domain; To didn't. Qualifying To the same way to test whether + # that asymmetry was the actual problem. resp = send_action([ ("Action", "MessageSend"), - ("To", "pjsip:{}".format(ext)), + ("To", "pjsip:{}@{}".format(ext, SMS_DOMAIN or "localhost")), ("From", from_uri), ("Body", body), ]) From 0135b2ed273015ec67539747832b95c5c49f25bd Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 27 Jul 2026 12:45:03 +0000 Subject: [PATCH 2/2] Use Destination, not To, for MessageSend's endpoint resolution `manager show command MessageSend` (this box's own Asterisk, requested live) documents Destination as the field that actually resolves an outgoing message's endpoint/technology; To is documented as a backward-compatible fallback for the destination when Destination is omitted, and separately as just the outgoing SIP MESSAGE's To: header content when Destination IS provided. Two live attempts using only To (bare "pjsip:212", then domain-qualified "pjsip:212@domain") both produced zero SIP wire traffic -- confirmed via `pjsip set logger on` during a real delivery attempt against an actively-registered contact -- meaning that documented fallback path isn't actually wired up on this Asterisk version regardless of what the docs promise. Switched to Destination using the docs' own "endpoint" form: bare "pjsip:", no domain, which resolves via the endpoint's default aor/contact -- the same live, registered contact `pjsip show contacts` already confirmed exists for this extension. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01JDyKC6Kdg7tofmYSmRtgww --- services/sms-inbound.sh | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/services/sms-inbound.sh b/services/sms-inbound.sh index 9c72b9a..5bcccef 100644 --- a/services/sms-inbound.sh +++ b/services/sms-inbound.sh @@ -333,12 +333,21 @@ def _ami_read_response(sock_file): def ami_deliver(from_number, to_exts, body): """Logs into AMI once and sends one MessageSend action per recipient. - UNVERIFIED against a real Asterisk instance as of this being written — - "message" as the AMI permission class, and To/From/Body as MessageSend's - exact parameter names, are both believed correct but haven't been - confirmed live. Every AMI response is logged in full specifically so the - first real delivery attempt shows exactly what Asterisk said if - something here is wrong, rather than failing silently. + "message" as the AMI permission class is confirmed live (login succeeds). + Destination (not To) is what actually resolves an outgoing message's + endpoint/technology -- confirmed against this box's own + `manager show command MessageSend`: To alone is documented as a + backward-compatible fallback for the destination, but live testing + (bare "pjsip:212", then "pjsip:212@domain", both for To with no + Destination) produced zero SIP wire traffic in either case -- `pjsip + set logger on` during a real attempt showed Asterisk never even tried + reaching the target's registered contact, so that fallback path isn't + actually wired up on this Asterisk version regardless of what the docs + promise. Destination's documented "endpoint" form -- bare "pjsip:", + no domain -- resolves via the endpoint's own default aor/contact, which + is exactly the live, registered contact `pjsip show contacts` already + confirmed exists. Every AMI response is still logged in full so the + next attempt is self-diagnosing if this isn't the whole fix either. Returns (delivered_count, total_count).""" if not AMI_SECRET: @@ -367,16 +376,9 @@ def ami_deliver(from_number, to_exts, body): from_uri = "".format(from_number or "unknown", SMS_DOMAIN or "localhost") for ext in to_exts: - # A bare "pjsip:{ext}" (no domain) for To, tried first, produced - # zero SIP wire traffic at all -- confirmed live via `pjsip set - # logger on` during a real delivery attempt, so the failure was - # happening at URI resolution inside Asterisk, before it ever - # tried to reach the registered contact. From already carried a - # domain; To didn't. Qualifying To the same way to test whether - # that asymmetry was the actual problem. resp = send_action([ ("Action", "MessageSend"), - ("To", "pjsip:{}@{}".format(ext, SMS_DOMAIN or "localhost")), + ("Destination", "pjsip:{}".format(ext)), ("From", from_uri), ("Body", body), ])