Class: SmsSenderUnverifiedAlertHandler

Inherits:
ApplicationJob
  • Object
show all
Includes:
RailsEventStore::AsyncHandler
Defined in:
app/subscribers/sms_sender_unverified_alert_handler.rb

Overview

Note:

PII is intentionally limited to the sender number (a WY-owned line)
and the SmsMessage id. The recipient (customer) phone is NOT logged or
sent to AppSignal — sender-side triage doesn't need it, and centralized
logs/APM dashboards are a high-fanout exposure surface.

Surfaces sender-side SMS delivery failures (toll-free unverified, A2P 10DLC
unregistered, region permission blocks) so they don't sit silent.
Recipient-side codes are routed to SmsRecipientDemoteHandler instead.

Logic Details

This is the alarm that would have caught the AppSignal trace re David
Grégoire (2026-05-06): every outbound from +18008755285 to a Canadian
mobile failed with ErrorCode 30032 for days, but the failures were only
visible by clicking individual SMS rows. With this subscriber, the same
shape trips a logged warning + AppSignal event tagged by (sender, code),
surfacing the toll-free verification debt directly.

Defined Under Namespace

Classes: SenderVerificationFailure

Constant Summary collapse

SENDER_VERIFICATION_CODES =

Sender-side codes — the sender is the unverified / unregistered party.

  • 30032 — Toll-Free Not Verified
  • 30034 — A2P 10DLC not registered
  • 21408 — Permission to send to this region disabled
  • 30002 — Account suspended
%w[30032 30034 21408 30002].freeze

Instance Method Summary collapse

Instance Method Details

#perform(event) ⇒ void

This method returns an undefined value.

Logs the failure and reports it to AppSignal (when active) keyed by
sender + code so multiple recurrences of the same sender problem group
into one incident.

Parameters:

  • event (Events::SmsSendFailed)

    domain event with at least
    error_code, sender, and sms_message_id in data



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'app/subscribers/sms_sender_unverified_alert_handler.rb', line 46

def perform(event)
  code = event.data[:error_code].to_s
  return unless SENDER_VERIFICATION_CODES.include?(code)

  sender = event.data[:sender]
  return if sender.blank?

  Rails.logger.warn(
    "[SmsSenderUnverifiedAlert] sender=#{sender} code=#{code} " \
    "sms_message_id=#{event.data[:sms_message_id]}"
  )

  return unless defined?(Appsignal) && Appsignal.active?

  Appsignal.report_error(SenderVerificationFailure.new("Twilio #{code}: sender not verified")) do |t|
    t.set_namespace('background')
    t.set_tags(sender: sender, error_code: code)
    t.add_custom_data(sms_message_id: event.data[:sms_message_id])
  end
end