Delphi SMS Client: Best Practices and Sample Code

Delphi SMS Client: Best Practices and Sample Code

Introduction

Sending SMS from Delphi applications remains a common requirement for notifications, two-factor authentication, and alerting systems. This article presents best practices for building a reliable, secure Delphi SMS client and provides compact sample code that demonstrates common workflows: sending an SMS via an HTTP-based SMS gateway, handling responses, and retrying failed deliveries.

Best Practices

1. Choose the right SMS gateway

  • Reliability: Pick a provider with high deliverability and SLAs.
  • API style: Prefer REST/HTTP JSON APIs over legacy protocols (SMPP) unless you need high throughput.
  • Coverage & cost: Ensure the provider supports the target countries and offers predictable pricing.
  • Delivery reports: Use gateways that provide delivery receipts (DLR) so you can confirm message status.

2. Secure credentials and configuration

  • Store secrets safely: Do not hard-code API keys. Use secure configuration (environment variables, encrypted config files).
  • Use HTTPS: Always call the gateway over TLS.
  • Rotate keys: Rotate API keys regularly and remove unused credentials.

3. Respect rate limits and quotas

  • Throttle requests: Implement client-side rate limiting to avoid being throttled or blocked.
  • Queueing: Use a queue (in-memory or persistent) for bursts. Process items at a controlled rate.

4. Implement robust error handling and retries

  • Differentiate errors: Retry on transient network or 5xx errors; do not retry on permanent 4xx errors (e.g., invalid number, unauthorized).
  • Backoff strategy: Use exponential backoff with jitter for retries.
  • Idempotency: Include a client-generated message ID where supported to avoid duplicate deliveries on retries.

5. Validate and format phone numbers

  • E.164 format: Normalize numbers to E.164 before sending.
  • Local rules: Apply country-specific validation to reduce provider rejections.

6. Monitor and log

  • Structured logs: Record API requests, responses, and delivery receipts (without logging secrets).
  • Metrics & alerts: Track success/failure rates, latency, and queue sizes. Alert on spikes in failures.

7. Handle delivery receipts and inbound messages

  • Webhook endpoint: Implement a secure webhook to receive DLRs and inbound messages; validate payloads (HMAC signature or token).
  • Idempotent processing: Ensure webhook handling is idempotent.

8. Cost control and user experience

  • Rate limits per user: Apply per-user rate limits to avoid abuse.
  • Message length & encoding: Be aware of concatenation and Unicode costs; prefer GSM-7 where possible.

Sample Code (Delphi, HTTP JSON REST)

Below is a concise example showing:

  • Sending an SMS via a REST gateway (POST JSON)
  • Basic response handling
  • Simple retry with exponential backoff

Note: Replace placeholders (API_URL, APIKEY) with your provider values. This example uses Indy (TIdHTTP) and System.JSON.

pascal

uses System.SysUtils, System.Classes, System.JSON, IdHTTP, IdSSLOpenSSL, IdGlobal; const API_URL = https://api.example-sms.com/v1/messages’; API_KEY = ‘YOUR_API_KEY’; // store securely, not in source type ESmsError = class(Exception); function PostJSON(const AUrl, AJson, AApiKey: string; out AResponse: string): Integer; var IdHTTP: TIdHTTP; SSLHandler: TIdSSLIOHandlerSocketOpenSSL; RequestStream, ResponseStream: TStringStream; begin IdHTTP := TIdHTTP.Create(nil); SSLHandler := TIdSSLIOHandlerSocketOpenSSL.Create(IdHTTP); RequestStream := TStringStream.Create(AJson, TEncoding.UTF8); ResponseStream := TStringStream.Create(, TEncoding.UTF8); try IdHTTP.IOHandler := SSLHandler; IdHTTP.Request.ContentType := ‘application/json; charset=utf-8’; IdHTTP.Request.CustomHeaders.Values[‘Authorization’] := ‘Bearer ‘ + AApiKey; try IdHTTP.Post(AUrl, RequestStream, ResponseStream); AResponse := ResponseStream.DataString; Result := IdHTTP.ResponseCode; except on E: EIdHTTPProtocolException do begin AResponse := E.ErrorMessage; Result := E.ErrorCode; Exit; end; on E: Exception do begin raise; end; end; finally IdHTTP.Free; SSLHandler.Free; RequestStream.Free; ResponseStream.Free; end; end; function SendSMS(const AToE164, ABody, AClientMsgId: string): string; var JsonObj: TJSONObject; JsonStr, Resp: string; Code, Attempt: Integer; BackoffMs: Integer; begin // Build JSON payload JsonObj := TJSONObject.Create; try JsonObj.AddPair(‘to’, AToE164); JsonObj.AddPair(‘body’, ABody); if AClientMsgId <> then JsonObj.AddPair(‘client_msg_id’, AClientMsgId); JsonStr := JsonObj.ToString; finally JsonObj.Free; end; // Simple retry with exponential backoff Attempt := 0; BackoffMs := 500; // start 500ms while Attempt < 5 do begin Inc(Attempt); try Code := PostJSON(API_URL, JsonStr, API_KEY, Resp); // Success 2xx if (Code >= 200) and (Code < 300) then begin Result := Resp; // provider response (JSON with message id etc.) Exit; end; // Client errors (4xx) - do not retry except 429 if (Code >= 400) and (Code < 500) and (Code <> 429) then raise ESmsError.CreateFmt(‘Permanent error %d: %s’, [Code, Resp]); // Otherwise transient - retry except on E: ESmsError do raise; on E: Exception do begin // treat as transient network error end; end; // Backoff with jitter Sleep(BackoffMs + Random(BackoffMs)); BackoffMs := BackoffMs * 2; end; raise ESmsError.Create(‘Failed to send SMS after retries’); end;

Notes on adapting the sample

  • Replace Indy with TNetHTTPClient or other HTTP libraries if preferred.
  • Parse provider JSON responses to extract provider message IDs and statuses.
  • Implement proper phone number normalization (use libphonenumber bindings or server-side validation).
  • Move API_KEY to secure storage and load at runtime.

Conclusion

A robust Delphi SMS client requires secure credential handling, phone number normalization, rate limiting, clear retry logic, and webhook-driven delivery receipt processing. The sample code gives a starting point for sending messages via an HTTP JSON API; extend it with validation, persistent queues, and observability for production use.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *