Mailgun
Send email through Mailgun with the @effect-kit/emails/mailgun Layer.
The @effect-kit/emails/mailgun subpath sends messages through Mailgun and provides the Email service.
Installation
npm install @effect-kit/emails effect mailgun.js@14.1.0 form-data@4.0.5Both packages are pinned peers and optional until you import this subpath.
Setup
Mailgun.layerConfig() reads these variables:
| Variable | Required | Value |
|---|---|---|
MAILGUN_API_KEY | yes | API key |
MAILGUN_DOMAIN | yes | Sending domain, such as mg.example.com |
MAILGUN_REGION | yes | us or eu |
Example (Sending a Message With Mailgun)
import { , , } from "effect";
import { } from "@effect-kit/emails";
import * as from "@effect-kit/emails/mailgun";
const = .().(
.(.(.())),
);
const = .(function* () {
const = yield* ;
return yield* .({
: "hello@example.com",
: "ada@example.com",
: "Welcome",
: "Your account is ready.",
});
});
.(.(.()));Use a from address your Mailgun account is allowed to send from.
Options
Mailgun.layer takes these options. layerConfig builds the same object from a Config.
Prop
Type
Capabilities
Mailgun reports this in email.capabilities:
| Text | HTML | Both | Sender name | Cc | Bcc | Reply-to | Headers | Attachments | Inline images | Idempotency |
|---|---|---|---|---|---|---|---|---|---|---|
| yes | yes | yes | yes | yes | yes | multiple | yes | yes | no | no |
These fail with UnsupportedFeatureError and acceptance: "notSubmitted" before any request:
- An attachment with a
contentId(featureinlineAttachments). - An
idempotencyKey(featureidempotency).
Idempotency
Not supported. A key fails with UnsupportedFeatureError before sending.
Provider notes
region: "eu"useshttps://api.eu.mailgun.netandregion: "us"useshttps://api.mailgun.net.endpointreplaces both.- Mailgun has no inline image support here. Every attachment goes out as a regular attachment, so a
contentIdfails before sending with featureinlineAttachments. - Install
form-datanext tomailgun.js. Both are pinned peers.
Using your own client
layerClient takes any object with messages.create(domain, message), which a mailgun.js client has. Unlike most providers its options are required, because they carry the domain.
Example (Borrowing a Mailgun Client)
import FormData from "form-data";
import Mailgun from "mailgun.js";
import * as MailgunEmail from "@effect-kit/emails/mailgun";
const client = new Mailgun(FormData).client({ username: "api", key: "fake-key" });
const EmailLive = MailgunEmail.layerClient(client, { domain: "mg.example.com" });You own a borrowed client. The Layer never closes it, and the client keeps its own retry, timeout and logging policy. The client is created with its own region and URL, so layerClient does not take a region.
Errors
ProviderConfigurationError carries provider: "mailgun" and a field naming the bad option. Layer construction fails with it, and layerClient fails with it for the client options.
field | Raised when |
|---|---|
timeout | The timeout is not finite and positive. |
token | The API key is not printable ASCII without spaces. |
region | The region is neither us nor eu. |
endpoint | The URL is not an http or https origin, or has credentials, a path, a query or a fragment. |
domain | The domain is not a valid hostname. |
Send failures use the HTTP status with the shared mapping: 401 is AuthenticationError, 403 PermissionDeniedError, 429 RateLimitedError, 400 and 422 InvalidMessageError, 5xx ProviderUnavailableError, and anything else ProviderError. acceptance is rejected for a 4xx status other than 409 and unknown otherwise. A network failure with no status is TransportError, and ETIMEDOUT or ECONNABORTED is TimeoutError, both with acceptance: "unknown". See Errors.