Skip to content
Browse the docs

Start here · Published 2026-09-29 · Updated 2026-09-29 · AgentiSend

SDKs

Install the Node, Python, PHP or Go client, or the MCP server and the CLI, and send one email.

Install one client and send one email. Node's package name on npm is agentisend. @agentisend/sdk-node is the same code. The other languages call the same HTTP API.

Node

npm install agentisend
/**
 * Send one email with the `agentisend` package.
 *
 * `agentisend` and `@agentisend/sdk-node` are the same client. This file is
 * the one the SDKs guide prints, and the examples suite runs it against a
 * real API with the fake transport.
 */
import { AgentiSend } from 'agentisend';

export async function sendHello(to: string): Promise<string> {
  const from = process.env.MAIL_FROM;
  if (!from) throw new Error('Set MAIL_FROM to an address on a domain you have verified.');
  const client = new AgentiSend(process.env.AGENTISEND_API_KEY, {
    baseUrl: process.env.AGENTISEND_BASE_URL,
  });
  const { id } = await client.emails.send(
    {
      from,
      to,
      subject: 'Hello from the Node SDK',
      text: 'Sent with the agentisend package.',
    },
    { idempotencyKey: `sdk-node/${to}` },
  );
  return id;
}
examples/node-sdk-send/send.ts, run by the test suite against a local AgentiSend server

Python

Python calls the API with the standard library. The package is not on PyPI yet. Until it is, this is the send:

"""Send one email with AgentiSend from Python, with nothing installed.

Set AGENTISEND_API_KEY and MAIL_FROM (an address on your verified domain), then: python3 send.py
"""
import json
import os
import urllib.error
import urllib.request

BASE_URL = os.environ.get("AGENTISEND_BASE_URL", "https://api.agentisend.com")

request = urllib.request.Request(
    f"{BASE_URL}/emails",
    method="POST",
    headers={
        "Authorization": f"Bearer {os.environ['AGENTISEND_API_KEY']}",
        "Content-Type": "application/json",
        # Named after the send, not the moment: a retry after a timeout replays it instead of mailing twice.
        "Idempotency-Key": "hello/someone@example.com",
    },
    data=json.dumps({
        "from": os.environ["MAIL_FROM"],
        "to": "someone@example.com",
        "subject": "Hello from AgentiSend",
        "text": "Ten minutes, start to sent.",
    }).encode(),
)
try:
    with urllib.request.urlopen(request, timeout=30) as response:
        print(json.load(response)["id"])
except urllib.error.HTTPError as err:
    # Every refusal carries a code and a fix that says what to do next.
    error = json.load(err).get("error", {})
    raise SystemExit(f"{error.get('code')}: {error.get('fix')}")
examples/python-send/send.py, run by the test suite against a local AgentiSend server

PHP

composer require agentisend/agentisend-php

The send, with no package loaded, is the request that client makes:

<?php
/**
 * Send one email over HTTP with the PHP standard library.
 *
 * No Composer package is loaded here. The install line on the SDKs page is
 * `composer require agentisend/agentisend-php`; this file is the request that
 * client makes, and the examples suite runs it.
 *
 * Set AGENTISEND_API_KEY, AGENTISEND_BASE_URL, MAIL_FROM and SEND_TO.
 */

declare(strict_types=1);

$base = getenv('AGENTISEND_BASE_URL') ?: 'https://api.agentisend.com';
$to = getenv('SEND_TO') ?: 'someone@example.com';
$body = json_encode([
    'from' => getenv('MAIL_FROM'),
    'to' => $to,
    'subject' => 'Hello from PHP',
    'text' => 'Sent with the PHP standard library.',
], JSON_THROW_ON_ERROR);

$context = stream_context_create([
    'http' => [
        'method' => 'POST',
        'header' => implode("\r\n", [
            'Authorization: Bearer ' . getenv('AGENTISEND_API_KEY'),
            'Content-Type: application/json',
            'Idempotency-Key: sdk-php/' . $to,
        ]),
        'content' => $body,
        'ignore_errors' => true,
        'timeout' => 30,
    ],
]);

$raw = file_get_contents($base . '/emails', false, $context);
$decoded = json_decode($raw === false ? '' : $raw, true);
if (!is_array($decoded) || !isset($decoded['id'])) {
    $error = is_array($decoded) && isset($decoded['error']) ? $decoded['error'] : [];
    $code = is_array($error) && isset($error['code']) ? $error['code'] : 'request_failed';
    $fix = is_array($error) && isset($error['fix']) ? $error['fix'] : '';
    fwrite(STDERR, $code . ': ' . $fix . PHP_EOL);
    exit(1);
}

echo $decoded['id'], PHP_EOL;
examples/php-send/send.php, run by the test suite against a local AgentiSend server

Go

The generated client is the module github.com/fortuneflick/agentisend-go. The send, with no module imported, is the request that client makes:

// Send one email over HTTP with the Go standard library.
//
// The module path of the generated client is github.com/fortuneflick/agentisend-go.
// This file does not import it. It is the request that client makes, and the
// examples suite runs it with `go run`.
//
// Set AGENTISEND_API_KEY, AGENTISEND_BASE_URL, MAIL_FROM and SEND_TO.
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

func main() {
	base := os.Getenv("AGENTISEND_BASE_URL")
	if base == "" {
		base = "https://api.agentisend.com"
	}
	to := os.Getenv("SEND_TO")
	if to == "" {
		to = "someone@example.com"
	}
	payload, err := json.Marshal(map[string]any{
		"from":    os.Getenv("MAIL_FROM"),
		"to":      to,
		"subject": "Hello from Go",
		"text":    "Sent with the Go standard library.",
	})
	if err != nil {
		fail(err)
	}
	request, err := http.NewRequest(http.MethodPost, base+"/emails", bytes.NewReader(payload))
	if err != nil {
		fail(err)
	}
	request.Header.Set("Authorization", "Bearer "+os.Getenv("AGENTISEND_API_KEY"))
	request.Header.Set("Content-Type", "application/json")
	request.Header.Set("Idempotency-Key", "sdk-go/"+to)
	client := &http.Client{Timeout: 30 * time.Second}
	response, err := client.Do(request)
	if err != nil {
		fail(err)
	}
	defer response.Body.Close()
	raw, err := io.ReadAll(response.Body)
	if err != nil {
		fail(err)
	}
	var decoded map[string]any
	if err := json.Unmarshal(raw, &decoded); err != nil {
		fail(err)
	}
	id, _ := decoded["id"].(string)
	if id == "" {
		fmt.Fprintln(os.Stderr, string(raw))
		os.Exit(1)
	}
	fmt.Println(id)
}

func fail(err error) {
	fmt.Fprintln(os.Stderr, err.Error())
	os.Exit(1)
}
examples/go-send/send.go, run by the test suite against a local AgentiSend server

MCP server

The hosted server is https://api.agentisend.com/mcp. A client that only speaks stdio installs the proxy:

npx @agentisend/mcp-server

The tool that sends is send_email. It calls the same POST /emails as the Node file above. Setup per client is on MCP.

CLI

npx @agentisend/sdk-node emails send --from "$MAIL_FROM" --to someone@example.com --subject "Hello" --text "Sent from the CLI."

agentisend is the command name once the package is installed. The full command list is the CLI.

Next