message.comDevelopers

Inbound addresses Live

Inbound addresses are the email addresses that, when emailed, become tickets in your workspace. Three flavours: an auto-generated address per workspace, custom localparts on our shared subdomain, or addresses on your own custom domain.

Address kinds

KindExampleSetup
auto[email protected]Created for every workspace on signup. Always works.
subdomain[email protected]Pick any local-part; we route on the workspace subdomain.
custom_domain[email protected]Requires a verified email domain.

List addresses

GET/api/v1/inbound-addressesAuth: Bearer

All addresses configured in the workspace.

Code samples

cURL
curl 'https://app.message.com/api/v1/inbound-addresses' \
  -H 'Authorization: Bearer YOUR_WORKSPACE_JWT'
JavaScript
const res = await fetch('https://app.message.com/api/v1/inbound-addresses', {
  headers: { Authorization: 'Bearer ' + token }
});
const { addresses } = await res.json();
Python
import requests
r = requests.get(
    "https://app.message.com/api/v1/inbound-addresses",
    headers={"Authorization": f"Bearer {token}"},
)
addresses = r.json()["addresses"]
Ruby
require "net/http"
require "json"
uri = URI("https://app.message.com/api/v1/inbound-addresses")
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
  req = Net::HTTP::Get.new(uri)
  req["Authorization"] = "Bearer #{token}"
  http.request(req)
end
addresses = JSON.parse(res.body)["addresses"]
PHP
<?php
$ctx = stream_context_create([
  "http" => ["method" => "GET", "header" => "Authorization: Bearer $token"]
]);
$addresses = json_decode(file_get_contents("https://app.message.com/api/v1/inbound-addresses", false, $ctx), true)["addresses"];

Create an address

POST/api/v1/inbound-addressesAuth: Bearer
FieldTypeDescription
kindrequiredenumOne of auto, subdomain, custom_domain.
localPartoptionalstringSubdomain only. The part before the @ sign. 1 to 64 chars.
addressoptionalstringCustom-domain only. Full address. The domain must be verified first.
departmentIdoptionaluuidRoute inbound mail at this address to this department.
Body (subdomain)
{
  "kind": "subdomain",
  "localPart": "support",
  "departmentId": "uuid"
}
200 OK
{
  "id": "uuid",
  "kind": "subdomain",
  "address": "[email protected]",
  "departmentId": "uuid",
  "verified": true,
  "createdAt": "2026-05-13T15:30:00Z"
}

Update routing

PATCH/api/v1/inbound-addresses/:idAuth: Bearer

Change the department, or update the local-part on a subdomain address. The address string regenerates accordingly.

Delete an address

DELETE/api/v1/inbound-addresses/:idAuth: Bearer

Mail to a deleted address bounces with a permanent failure. Existing tickets stay in the inbox.

Sending a test email

The fastest way to verify routing is to email the address from your phone. The inbound webhook fires within a few seconds; check Settings → Logs for the trace if nothing arrives. Most failures are SPF or DMARC misconfiguration on the sending side.

If you forward from Gmail or Microsoft 365, see the tutorials: Gmail forwarding and Microsoft 365 forwarding.

Errors

CodeWhen
400 invalid_bodyPayload validation failed.
409 conflictAn address with this local-part / address already exists.
422 domain_unverifiedCustom-domain address attempted without a verified domain.

Common pitfalls

  • Using a free email provider for the local-part on a custom domain. Forwarding from Gmail to message.com works; using a Gmail address as your inbound address does not. You need a domain you control.
  • Forgetting SPF / DKIM / DMARC. Custom-domain inbound needs working DNS. The dashboard surfaces a checklist; verify all three are green.
  • Routing to a deleted department. The inbound webhook will still create a ticket but it lands in the workspace queue, not a specific dept.