Enviar um e-mail
POST https://api.spacepost.dev/emails
Envie um e-mail para até 50 destinatários em to, com cc, bcc, anexos, tags, cabeçalhos e agendamento opcionais. A chamada retorna assim que o e-mail é aceito e colocado na fila; a entrega acontece de forma assíncrona e é informada por webhooks.
Exemplo
Seção intitulada “Exemplo”import { SpacePost } from "@spacepost/node";
const spacepost = new SpacePost(process.env.SPACEPOST_API_KEY);
const { data, error } = await spacepost.emails.send({ from: "Acme <hello@acme.com>", to: ["user@example.com"], cc: ["manager@example.com"], bcc: ["archive@acme.com"], replyTo: "support@acme.com", subject: "Your invoice", html: "<p>Invoice attached.</p>", text: "Invoice attached.", headers: { "X-Entity-Ref-ID": "inv_1042" }, tags: [{ name: "category", value: "invoice" }],});
if (error) { console.error(error.statusCode, error.name, error.message);} else { console.log("Email id:", data.id);}curl -X POST https://api.spacepost.dev/emails \ -H "Authorization: Bearer $SPACEPOST_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "from": "Acme <hello@acme.com>", "to": ["user@example.com"], "cc": ["manager@example.com"], "bcc": ["archive@acme.com"], "reply_to": "support@acme.com", "subject": "Your invoice", "html": "<p>Invoice attached.</p>", "text": "Invoice attached.", "headers": { "X-Entity-Ref-ID": "inv_1042" }, "tags": [{ "name": "category", "value": "invoice" }] }'import os, requests
r = requests.post( "https://api.spacepost.dev/emails", headers={"Authorization": f"Bearer {os.environ['SPACEPOST_API_KEY']}"}, json={ "from": "Acme <hello@acme.com>", "to": ["user@example.com"], "cc": ["manager@example.com"], "bcc": ["archive@acme.com"], "reply_to": "support@acme.com", "subject": "Your invoice", "html": "<p>Invoice attached.</p>", "text": "Invoice attached.", "headers": {"X-Entity-Ref-ID": "inv_1042"}, "tags": [{"name": "category", "value": "invoice"}], },)print(r.json())payload := map[string]any{ "from": "Acme <hello@acme.com>", "to": []string{"user@example.com"}, "cc": []string{"manager@example.com"}, "reply_to": "support@acme.com", "subject": "Your invoice", "html": "<p>Invoice attached.</p>", "tags": []map[string]string{{"name": "category", "value": "invoice"}},}b, _ := json.Marshal(payload)req, _ := http.NewRequest("POST", "https://api.spacepost.dev/emails", bytes.NewReader(b))req.Header.Set("Authorization", "Bearer "+os.Getenv("SPACEPOST_API_KEY"))req.Header.Set("Content-Type", "application/json")res, err := http.DefaultClient.Do(req)$ch = curl_init('https://api.spacepost.dev/emails');curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('SPACEPOST_API_KEY'), 'Content-Type: application/json'], CURLOPT_POSTFIELDS => json_encode([ 'from' => 'Acme <hello@acme.com>', 'to' => ['user@example.com'], 'reply_to' => 'support@acme.com', 'subject' => 'Your invoice', 'html' => '<p>Invoice attached.</p>', 'tags' => [['name' => 'category', 'value' => 'invoice']], ]),]);echo curl_exec($ch);require "net/http"require "json"
uri = URI("https://api.spacepost.dev/emails")req = Net::HTTP::Post.new(uri, "Authorization" => "Bearer #{ENV["SPACEPOST_API_KEY"]}", "Content-Type" => "application/json")req.body = { from: "Acme <hello@acme.com>", to: ["user@example.com"], reply_to: "support@acme.com", subject: "Your invoice", html: "<p>Invoice attached.</p>", tags: [{ name: "category", value: "invoice" }]}.to_jsonres = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |h| h.request(req) }puts res.body{ "id": "0192e1c4-7a3b-7c1e-9d2f-3b5a8e6f4c10" }Corpo da requisição
Seção intitulada “Corpo da requisição”fromstringobrigatórioRemetente, no formato email@domain.com ou Name <email@domain.com>. O domínio (ou um domínio pai) deve estar verificado. A única exceção é onboarding@test.spacepost.dev; veja Testes.
tostring | string[]obrigatórioDestinatários. Até 50 endereços.
subjectstringobrigatórioDe 1 a 998 caracteres.
htmlstringopcionalCorpo em HTML. Pelo menos um entre html e text é obrigatório.
textstringopcionalCorpo em texto simples. Se você enviar apenas html, uma alternativa em texto é gerada para você, o que melhora a entregabilidade.
ccstring | string[]opcionalAté 50 endereços.
bccstring | string[]opcionalAté 50 endereços. Nunca é gravado nos cabeçalhos da mensagem.
reply_tostring | string[]opcionalAté 50 endereços. O alias em camelCase replyTo também é aceito.
scheduled_atstringopcionalData ISO 8601 ou linguagem natural, como in 1 hour, com no máximo 30 dias de antecedência. Alias scheduledAt.
headersobjectopcionalCabeçalhos personalizados, com chaves e valores do tipo string.
attachmentsobject[]opcionalAté 50 anexos, cada um com filename e exatamente um entre content e path.
tagsobject[]opcionalAté 50 pares { name, value }. Nomes e valores: de 1 a 256 caracteres entre A-Z a-z 0-9 _ -.
tenant_idstringopcionalModo plataforma: envia em nome de um tenant (nosso id ou o seu external_id). Opcional quando o domínio de from pertence a um tenant. Alias tenantId no SDK para Node. Veja Modo plataforma.
Veja também: verificação de domínio, Testes, Agendamento, Cabeçalhos personalizados, Anexos, Tags, Modo plataforma.
Os endereços de todos os campos podem usar o formato Name <email@domain.com>.
Limites resumidos
Seção intitulada “Limites resumidos”| Limite | Valor |
|---|---|
Destinatários por campo (to, cc, bcc, reply_to) |
50 |
| Tamanho do assunto | 998 caracteres |
| Anexos | 50 por e-mail, filename com até 255 caracteres |
| Tags | 50 por e-mail, nome e valor de 1 a 256 caracteres entre A-Z a-z 0-9 _ - |
| Tamanho total da mensagem | 40 MB, incluindo anexos e a sobrecarga de codificação |
| Horizonte de agendamento | 30 dias |
| E-mails por requisição em lote | 100 (Envio em lote) |
Resposta
Seção intitulada “Resposta”O sucesso retorna 200 com o id do novo e-mail (um UUIDv7). Use-o com GET /emails/{id} para ler o e-mail e o respectivo last_event.
O que pode dar errado
Seção intitulada “O que pode dar errado”| Status | name |
Significado |
|---|---|---|
| 401 | missing_api_key |
Falta o cabeçalho Authorization: Bearer. |
| 403 | invalid_api_key |
A chave é desconhecida, foi revogada ou não é uma chave do SpacePost (sp_live_...). |
| 401 | restricted_api_key |
Uma chave restrita a um domínio foi usada com um domínio de from diferente. |
| 403 | invalid_from_address |
O domínio de from não está verificado para a sua equipe. |
| 403 | validation_error |
Uso de test.spacepost.dev como remetente com um destinatário que não é membro da equipe nem um endereço de teste. |
| 403 | sending_paused |
Sua equipe está pausada. |
| 422 | validation_error |
Um campo está ausente ou é inválido. A message indica o campo, por exemplo `to`: Invalid email address. |
| 429 | daily_quota_exceeded |
Limite diário atingido: o sandbox de conta nova, o limite do seu nível de confiança ou o daily_limit de um tenant. |
| 429 | monthly_quota_exceeded |
O limite mensal do plano Free foi atingido. |
| 429 | rate_limit_exceeded |
Mais requisições por segundo do que o seu limite. Veja Limites de taxa. |
Veja a lista completa em Erros.
Depois da chamada
Seção intitulada “Depois da chamada”O e-mail passa por vários status, expostos como last_event: queued (ou scheduled), sent e, depois, delivered, delivery_delayed, bounced, complained, opened ou clicked. Se todos os destinatários estiverem na sua lista de supressão, nada é enviado e o status passa a ser suppressed.