Skip to content

Using an Unlisted Provider

These pages list popular services because they're popular — not because they're the only ones that work. The provider you actually need may be a regional email service in Poland, a national SMS gateway, your company's internal alerting API, or a niche platform nobody outside your industry has heard of. This chapter is the qualification guide: how to look at any provider's documentation and determine, in a few minutes, whether and how pg_relay can reach it — and what the path is when it can.

The decision comes down to one question first:

Does it speak SMTP?

If yes, you're done — build the profile yourself, today. The smtp transport doesn't know or care who operates the server; every SMTP recipe in this book is just this checklist filled in with one vendor's answers. Pull these six facts from your provider's documentation (usually a page named "SMTP settings" or "server settings"):

What to find Becomes What the docs usually call it
Server hostname host "SMTP server", "outgoing mail server"
Port port 587 (submission), 465 (SSL/TLS), 25, sometimes 2525
Encryption mode security "STARTTLS" → starttls; "SSL/TLS", "implicit TLS" → tls; none → none
Auth mechanism auth "PLAIN"/"password" → plain; "LOGIN" → login; IP-allow-listed → none
Username username Watch for magic values — some services use a literal fixed string (SendGrid: apikey; Resend: resend) or the API key itself
Password password Always as an _env: reference; often an API key or a purpose-made "SMTP password" rather than your dashboard login

Then follow Your Own SMTP Server's testing sequence — validate_profile(), one debug-traced send, read the trace. Vendor quirks to expect: a required sender-domain verification step (unverified from5xx, permanent), regional hostnames (smtp.eu.…), and multiple ports for firewall evasion. That's the whole integration; nothing about it involves this project's maintainers.

(A provider whose SMTP endpoint demands OAuth2 — increasingly common for Microsoft- and Google-hosted mail — is also self-serve: auth: "oauth2" covers both grant varieties, with a worked example of each and guidance for fitting an unlisted XOAUTH2 server in SMTP Endpoints.)

If it's an HTTP API: run the four-part fit test

REST providers are reached through the webhook transport, and whether one fits is determined by four questions you can answer from its API documentation without writing a line of code. This is the same test every assessed provider in the SMS and Incident Alerting chapters was put through.

1. Is authentication a static value attached to a single request? The transport can express: a bearer token (Authorization: Bearer …), any custom header (which covers vendor schemes like App <key> or GenieKey <key> — store the whole header value in the environment variable), HTTP Basic, a key embedded in the URL (store the whole URL as the secret), or a credential inside the request body (the profile's body_merge overlay injects it — see the body_merge section). What it cannot express: a login flow that exchanges credentials for a session token, OAuth token endpoints, or per-request cryptographic signing (AWS SigV4, JWT assertions). A provider requiring those is structurally out — that's what excludes AWS SNS and OnPage.

2. Is the request body JSON, or flat form-encoded? JSON of any shape works (the default). application/x-www-form-urlencoded works when the fields are flat scalars (body_style: "form" — Twilio's shape). multipart/form-data does not — that's what excludes Mailgun's REST API (its SMTP endpoint is the route instead).

3. Can success and failure be read from the response? You need to be able to state rules like "2xx → sent, id from the body; 429/5xx/no-response → retry; other 4xx → failed". Almost every API passes this trivially. The traps are providers that answer 200 and bury the real outcome in the body (Slack does; Infobip does) — that's fine, it just means the classification rules read the body — and providers that report final outcomes only via callbacks to your endpoint: pg_relay deliberately has no inbound HTTP listener, so a callback-only status model reduces to "accepted means sent".

4. Is one POST one notification? The transport sends exactly one uninterpreted request per delivery attempt. Multi-step conversations — reserve-then-commit, upload-then-attach, paginated anything — don't fit.

Pass all four and the provider is compatible. Now the honest part:

Compatible ≠ selectable — webhook providers ship as adapters

Unlike SMTP, you cannot point create_profile() at an arbitrary webhook provider today: request rendering and response classification live in this extension as a curated adapter per provider (p_provider is CHECK-constrained to adapters that exist — currently slack). That's a deliberate security posture — every reachable code path is enumerable and auditable, nothing dispatches on data — and it means a new provider is a small, self-contained extension change rather than something a profile can improvise.

What to do with your fit-test results, in order of preference: request the adapter (open an issue with the four answers above — endpoint, auth style, body shape, response rules; that's genuinely most of the work, and adapters need no pg_relay release); contribute it (an adapter is one render function and one classification branch in SQL, patterned exactly on the Slack pair); or — for an internal API you control — consider making your service accept what an existing adapter emits, which is occasionally the shortest path of all.

Worked example: qualifying a fictional regional provider

Suppose your Polish email provider "PocztaAPI" documents: POST https://api.poczta-example.pl/v2/send, header X-Api-Key: <key>, JSON body {"od": …, "do": […], "temat": …, "tresc_html": …}, responses 201 with {"id_wiadomosci": …}, 429 on rate limit, 4xx with {"blad": …}.

The fit test: static header auth (custom_header, header_name: "X-Api-Key") ✓; JSON body ✓; classifiable (201 → sent with id_wiadomosci; 429/5xx/0 → retry; other 4xx → failed with blad) ✓; one POST per message ✓. Fully compatible — those four lines are the adapter specification, ready to file or implement. And if PocztaAPI also publishes SMTP settings, you don't need to wait for any of it.


Next: Email Services — the popular ones, pre-assessed.