Skip to content

Client SDKs

Typed, high-level libraries for the Developer API in TypeScript, Python and Go: read, reply to, wait for and send mail in a few lines.

Each SDK gives you the same small vocabulary - connect once, name inboxes by email address, and work with message objects that can reply, forward, mark themselves read or move to Trash. Every operation in the API reference is covered, including waiting for a message to arrive (handy for sign-in codes in end-to-end tests). All three need an API key, which is part of the Pro plan.

TypeScript / JavaScript

Published to npm as @anymail/sdk. ESM, fully typed, no runtime dependencies.

Install

npm install @anymail/sdk

Quick start

import { Anymail } from '@anymail/sdk';

await Anymail.connect({ apiKey: process.env.ANYMAIL_API_KEY! });

// Inboxes are named by address - no ids to look up first.
for (const message of await Anymail.getMessages({ inbox: 'support@acme.com', unread: true })) {
  await message.reply({ text: 'Thanks - we are on it.' });
  await message.markAsRead();
}

await Anymail.sendMessage({
  from: 'support@acme.com',
  to: 'jo@example.com',
  subject: 'Your report',
  html: '<p>Attached.</p>',
  attachments: [{ filename: 'report.pdf', content: pdfBytes }]
});

// In an end-to-end test: wait for the sign-in code.
const mail = await Anymail.waitForMessage({ inbox: 'signup@acme.com', contains: /\d{6}/ });

Python

Published to PyPI as anymail-sdk. Python 3.9+, built on httpx.

Install

pip install anymail-sdk

Quick start

from anymail_sdk import Anymail

Anymail.connect("am_...")  # or set ANYMAIL_API_KEY

# Inboxes are named by address - no ids to look up first.
for message in Anymail.get_messages(inbox="support@acme.com", unread=True):
    message.reply("Thanks - we're on it.")
    message.mark_as_read()

Anymail.send_message(
    from_="support@acme.com",
    to="jo@example.com",
    subject="Your report",
    html="<p>Attached.</p>",
    attachments=[{"filename": "report.pdf", "content": pdf_bytes}],
)

# In an end-to-end test: wait for the sign-in code.
mail = Anymail.wait_for_message(inbox="signup@acme.com", contains="code", timeout=30)

Go

Served by AnyMail's own Go module proxy as anymail.tech/sdk/go - there is no public registry entry, so GOPROXY points at it for this one command and GOSUMDB is turned off because the public checksum database has never seen the module.

Install

GOPROXY=https://anymail.tech/api/sdk-artifacts/goproxy GOSUMDB=off go get anymail.tech/sdk/go@latest

Quick start

import anymailsdk "anymail.tech/sdk/go"

mail, err := anymailsdk.Connect(ctx, anymailsdk.Options{APIKey: os.Getenv("ANYMAIL_API_KEY")})
if err != nil {
	log.Fatal(err)
}

// Inboxes are named by address - no ids to look up first.
messages, err := mail.GetMessages(ctx, anymailsdk.MessageFilter{Inbox: "support@acme.com", Unread: true})
for _, message := range messages {
	_, err = message.Reply(ctx, anymailsdk.ReplyOptions{Text: "Thanks - we're on it."})
	err = message.MarkAsRead(ctx)
}

_, err = mail.SendMessage(ctx, anymailsdk.OutgoingMessage{
	From: "support@acme.com", To: "jo@example.com", Subject: "Your report", HTML: "<p>Attached.</p>",
	Attachments: []anymailsdk.OutgoingAttachment{{Filename: "report.pdf", Content: pdfBytes}},
})

// In an end-to-end test: wait for the sign-in code.
code, err := mail.WaitForMessage(ctx, anymailsdk.WaitOptions{Inbox: "signup@acme.com", Contains: "code"})