Envoyer un e-mail
POST https://api.spacepost.dev/emails
Envoyez un e-mail à 50 destinataires to au maximum, avec cc, bcc, pièces jointes, tags, en-têtes et planification en option. L’appel retourne dès que l’e-mail est accepté et mis en file ; la distribution se fait de manière asynchrone et est signalée par des webhooks.
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" }Corps de la requête
Section intitulée « Corps de la requête »fromstringrequisExpéditeur, sous la forme email@domain.com ou Name <email@domain.com>. Le domaine (ou un domaine parent) doit être vérifié. La seule exception est onboarding@test.spacepost.dev, voir Tests.
tostring | string[]requisDestinataires. Jusqu'à 50 adresses.
subjectstringrequisDe 1 à 998 caractères.
htmlstringfacultatifCorps HTML. Au moins un des champs html ou text est requis.
textstringfacultatifCorps en texte brut. Si vous n'envoyez que html, une alternative texte est générée pour vous, ce qui améliore la délivrabilité.
ccstring | string[]facultatifJusqu'à 50 adresses.
bccstring | string[]facultatifJusqu'à 50 adresses. Jamais écrites dans les en-têtes du message.
reply_tostring | string[]facultatifJusqu'à 50 adresses. L'alias camelCase replyTo est également accepté.
scheduled_atstringfacultatifDate ISO 8601 ou langage naturel comme in 1 hour, au plus 30 jours à l'avance. Alias scheduledAt.
headersobjectfacultatifEn-têtes personnalisés, avec des clés et des valeurs de type chaîne.
attachmentsobject[]facultatifJusqu'à 50 pièces jointes, chacune avec filename et exactement un des champs content ou path.
tagsobject[]facultatifJusqu'à 50 paires { name, value }. Noms et valeurs : de 1 à 256 caractères parmi A-Z a-z 0-9 _ -.
tenant_idstringfacultatifMode plateforme : envoyer au nom d'un tenant (notre id ou votre external_id). Facultatif lorsque le domaine from appartient à un tenant. Alias tenantId dans le SDK Node. Voir Mode plateforme.
Voir aussi : vérification du domaine, Tests, Planification, En-têtes personnalisés, Pièces jointes, Tags, Mode plateforme.
Les adresses de tous les champs peuvent utiliser la forme Name <email@domain.com>.
Les limites en un coup d’œil
Section intitulée « Les limites en un coup d’œil »| Limite | Valeur |
|---|---|
Destinataires par champ (to, cc, bcc, reply_to) |
50 |
| Longueur de l’objet | 998 caractères |
| Pièces jointes | 50 par e-mail, filename jusqu’à 255 caractères |
| Tags | 50 par e-mail, nom et valeur de 1 à 256 caractères parmi A-Z a-z 0-9 _ - |
| Taille totale du message | 40 Mo, pièces jointes et surcoût d’encodage compris |
| Horizon de planification | 30 jours |
| E-mails par requête de lot | 100 (Envoi par lot) |
En cas de succès, la réponse est 200 avec l’id du nouvel e-mail (un UUIDv7). Utilisez-le avec GET /emails/{id} pour lire l’e-mail et son last_event.
Ce qui peut mal tourner
Section intitulée « Ce qui peut mal tourner »| Statut | name |
Signification |
|---|---|---|
| 401 | missing_api_key |
Aucun en-tête Authorization: Bearer. |
| 403 | invalid_api_key |
La clé est inconnue, révoquée ou n’est pas une clé SpacePost (sp_live_...). |
| 401 | restricted_api_key |
Une clé restreinte à un domaine a été utilisée avec un autre domaine from. |
| 403 | invalid_from_address |
Le domaine from n’est pas vérifié pour votre équipe. |
| 403 | validation_error |
test.spacepost.dev utilisé comme expéditeur avec un destinataire qui n’est ni membre de l’équipe ni une adresse de test. |
| 403 | sending_paused |
Votre équipe est en pause. |
| 422 | validation_error |
Un champ est manquant ou invalide. message nomme le champ, par exemple `to`: Invalid email address. |
| 429 | daily_quota_exceeded |
Limite quotidienne atteinte : la sandbox des nouveaux comptes, le plafond de votre niveau de confiance ou la daily_limit d’un tenant. |
| 429 | monthly_quota_exceeded |
Limite mensuelle du forfait Free atteinte. |
| 429 | rate_limit_exceeded |
Dépassement de votre limite de requêtes par seconde. Voir Limites de débit. |
Voir la liste complète dans Erreurs.
Après l’appel
Section intitulée « Après l’appel »L’e-mail traverse plusieurs statuts, exposés dans last_event : queued (ou scheduled), sent, puis delivered, delivery_delayed, bounced, complained, opened ou clicked. Si tous les destinataires figurent dans votre liste de suppression, rien n’est envoyé et le statut devient suppressed.