SDK Python

Este guia mostra como instalar e usar o SDK Python. O pacote no PyPI se chama usesend — é o SDK do projeto open-source que dá origem ao Madmail, e é esse nome que você instala e importa.

Instalação

Instale pelo PyPI:

pip install usesend

Inicialização

from usesend import UseSend, types


# Opção A: passar os valores direto (prático em scripts e testes)
client = UseSend("us_xxx")

# Opção B: URL base própria (instância self-hosted)
client = UseSend("us_xxx", url="https://app.madmail.com.br")

Enviar um email

EmailCreate é um TypedDict, serve só para o editor te ajudar; em tempo de execução você passa um dict comum. O cliente aceita from ou from_ (ele normaliza from_ para from).

from usesend import UseSend, types

client = UseSend("us_xxx")

payload: types.EmailCreate = {
    "to": "cliente@exemplo.com.br",
    "from": "nao-responda@suaempresa.com.br",
    "subject": "Boas-vindas",
    "html": "<strong>Olá!</strong>",
    "headers": {"X-Campaign": "boas-vindas"},
}

data, err = client.emails.send(payload)
print(data or err)

O Madmail repassa os seus cabeçalhos personalizados para o SES. Só os cabeçalhos X-Usesend-Email-ID e References são controlados automaticamente.

Anexos e agendamento:

from datetime import datetime, timedelta

payload: types.EmailCreate = {
    "to": ["cliente1@exemplo.com.br", "cliente2@exemplo.com.br"],
    "from": "nao-responda@suaempresa.com.br",
    "subject": "Relatório",
    "text": "Segue em anexo.",
    "attachments": [
        {"filename": "relatorio.txt", "content": "SGVsbG8gd29ybGQ="},  # base64
    ],
    "scheduledAt": datetime.utcnow() + timedelta(minutes=10),
}
data, err = client.emails.create(payload)

Envio em lote

items: list[types.EmailBatchItem] = [
    {"to": "a@exemplo.com.br", "from": "nao-responda@suaempresa.com.br", "subject": "A", "html": "<p>A</p>"},
    {"to": "b@exemplo.com.br", "from": "nao-responda@suaempresa.com.br", "subject": "B", "html": "<p>B</p>"},
]
data, err = client.emails.batch(items)

Consultar e gerenciar emails

Buscar um email:

email, err = client.emails.get("email_123")

Mudar o horário do agendamento:

from datetime import datetime, timedelta

update: types.EmailUpdate = {"scheduledAt": datetime.utcnow() + timedelta(hours=1)}
data, err = client.emails.update("email_123", update)

Cancelar um email agendado:

data, err = client.emails.cancel("email_123")

Contatos

Toda operação com contatos precisa do id da lista de contatos (book_id).

Criar um contato:

create: types.ContactCreate = {
    "email": "cliente@exemplo.com.br",
    "firstName": "Ana",
    "properties": {"plan": "pro"},
}
data, err = client.contacts.create("book_123", create)

Buscar um contato:

contact, err = client.contacts.get("book_123", "contact_456")

Atualizar um contato:

update: types.ContactUpdate = {"subscribed": False}
data, err = client.contacts.update("book_123", "contact_456", update)

Criar ou atualizar (upsert) um contato:

upsert: types.ContactUpsert = {
    "email": "cliente@exemplo.com.br",
    "firstName": "Ana",
}
data, err = client.contacts.upsert("book_123", "contact_456", upsert)

Excluir um contato:

data, err = client.contacts.delete(book_id="book_123", contact_id="contact_456")

Tratamento de erros

Por padrão o cliente levanta UseSendHTTPError em respostas que não sejam 2xx. Para receber o erro como valor de retorno, passe raise_on_error=False.

from usesend import UseSend, UseSendHTTPError

# Levanta exceção em caso de erro (padrão)
client = UseSend("us_xxx")
try:
    data, _ = client.emails.get("email_123")
except UseSendHTTPError as e:
    print("a requisição falhou:", e)

# Retorna (None, erro) em vez de levantar
client = UseSend("us_xxx", raise_on_error=False)
data, err = client.emails.get("email_123")
if err:
    print("erro:", err)