SendlySendly
Migrate from

Migrate from Mailgun

Point the Mailgun SDK (mailgun.js) at Sendly with a URL override and a Sendly key

Sendly implements Mailgun's POST /v3/<domain>/messages. Keep the official mailgun.js SDK — change the URL and the API key.

  • Base URL: https://api.sendly.now/api/compat/mailgun (the SDK appends /v3/<domain>/messages)
  • Auth: HTTP Basic api:<sk_...> — Mailgun's basic-auth style, where the username is the literal api and the password is your key. Use a Sendly secret key as the key.

Mailgun does not publish an official Python SDK. Python senders can call the compat endpoint over plain HTTP (multipart/form-data) or use the Sendly Python SDK.

The two-variable swap

Before (Mailgun)
import formData from "form-data";
import Mailgun from "mailgun.js";

const mailgun = new Mailgun(formData);
const mg = mailgun.client({ username: "api", key: "your-mailgun-key" });

await mg.messages.create("yourdomain.com", {
  from: "you@yourdomain.com",
  to: "customer@example.com",
  subject: "Hello",
  html: "<p>Welcome aboard.</p>",
});
After (Sendly)
import formData from "form-data";
import Mailgun from "mailgun.js";

const mailgun = new Mailgun(formData);
const mg = mailgun.client({
  username: "api",
  key: "sk_your_sendly_key",
  url: "https://api.sendly.now/api/compat/mailgun",
});

await mg.messages.create("yourdomain.com", {
  from: "you@yourdomain.com",
  to: "customer@example.com",
  subject: "Hello",
  html: "<p>Welcome aboard.</p>",
});

The domain in the URL path (yourdomain.com above) must match the domain of your from address. A mismatch returns a 400 in Mailgun's error shape.

API reference

The one operation this dialect covers, with its full request and response schema:

Supported fields

FieldSupportNotes
fromFullMust be on a verified domain that matches the URL path.
toFullRepeatable, as Mailgun sends it.
cc / bccFull
subjectFull
html / textFullhtml is preferred when both are present. At least one is required.
h:X-* headersFullThe h: prefix is stripped.
o:tagPartialRepeatable; mapped to Sendly tags (sanitized).
attachmentFullFile parts are read and attached.

Success comes back in Mailgun's shape: { "id": "<id@domain>", "message": "Queued. Thank you." }.

Not supported

Mailgun options beyond o:tag — scheduled delivery (o:deliverytime), tracking toggles, and stored templates — are not applied; only the fields in the table above are honored. Auth, validation, and domain-match failures return Mailgun's bare { "message": ... } error body with the matching status (a bad key is 401), so mailgun.js's own error handling (error.status / error.details) fires as it does today.

On this page