Nutze Xitroo aus deinem eigenen Code: Bestätigungsmails in End-to-End-Tests empfangen,
Registrierungen automatisieren oder E-Mails von jeder @xitroo.de-Adresse senden.
Wähl unten Developer, Team oder Business und klick auf Abonnieren.
Karte oder andere Zahlarten. Monatlich in US-Dollar, Rechnung per E-Mail, jederzeit kündbar.
Dein Schlüssel (xit_…) erscheint direkt nach der Zahlung und kommt zusätzlich per E-Mail.
Schlüssel verloren? Neuen anfordern →
zzgl. anfallender Umsatzsteuer, monatlich in US-Dollar abgerechnet, jederzeit kündbar
Tarif wechseln, Zahlungsdaten ändern, Rechnungen herunterladen oder kündigen. Gib deinen API-Schlüssel ein.
Gib die E-Mail-Adresse deines Abos ein. Wir schicken dir einen neuen Schlüssel, der alte gilt dann nicht mehr.
xit_.X-Api-Key mit.@xitroo.de, @xitroo.com oder @xitroo.fr funktioniert sofort. E-Mails werden nach 48 Stunden gelöscht.curl -H "X-Api-Key: $XITROO_API_KEY" \
"https://api.xitroo.com/v1/mails?mailAddress=mein-test-42@xitroo.de&mailsPerPage=25&minTimestamp=0&maxTimestamp=$(date +%s)&locale=de"
Basis-URL: https://api.xitroo.com/v1 · alle Antworten sind JSON · der Schlüssel gehört nie in die URL.
Getesteter Code in acht Sprachen. Setz die Umgebungsvariable XITROO_API_KEY auf deinen Schlüssel.
ADDRESS="my-test-42@xitroo.com"
SINCE=$(date +%s)
# ... sign up with $ADDRESS in your app ...
while :; do
sleep 2
ID=$(curl -s -H "X-Api-Key: $XITROO_API_KEY" \
"https://api.xitroo.com/v1/mails?mailAddress=$ADDRESS&mailsPerPage=10&minTimestamp=$SINCE&maxTimestamp=$(( $(date +%s) + 60 ))&locale=en" \
| jq -r '.mails[0]._id // empty')
[ -n "$ID" ] && break
done
curl -s -H "X-Api-Key: $XITROO_API_KEY" \
"https://api.xitroo.com/v1/mail?id=$ID&locale=en" | jq -r .subject
<?php
$api = 'https://api.xitroo.com/v1';
$ctx = stream_context_create(['http' => [
'header' => 'X-Api-Key: ' . getenv('XITROO_API_KEY'),
'ignore_errors' => true,
]]);
$address = 'my-test-42@xitroo.com';
$since = time();
// ... sign up with $address in your app ...
do {
sleep(2);
$query = http_build_query([
'mailAddress' => $address, 'mailsPerPage' => 10, 'locale' => 'en',
'minTimestamp' => $since, 'maxTimestamp' => time() + 60,
]);
$list = json_decode(file_get_contents("$api/mails?$query", false, $ctx), true);
} while (empty($list['mails']));
$id = $list['mails'][0]['_id'];
$mail = json_decode(file_get_contents("$api/mail?id=$id&locale=en", false, $ctx), true);
echo $mail['subject'], PHP_EOL;
// Node.js 18+, save as wait.mjs
const API = "https://api.xitroo.com/v1";
const headers = { "X-Api-Key": process.env.XITROO_API_KEY };
const address = "my-test-42@xitroo.com";
const since = Math.floor(Date.now() / 1000);
// ... sign up with address in your app ...
let list;
do {
await new Promise((r) => setTimeout(r, 2000));
const q = new URLSearchParams({
mailAddress: address, mailsPerPage: 10, locale: "en",
minTimestamp: since, maxTimestamp: Math.floor(Date.now() / 1000) + 60,
});
list = await (await fetch(`${API}/mails?${q}`, { headers })).json();
} while (!list.mails);
const id = list.mails[0]._id;
const mail = await (await fetch(`${API}/mail?id=${id}&locale=en`, { headers })).json();
console.log(mail.subject);
import os, time, requests
API = "https://api.xitroo.com/v1"
HEADERS = {"X-Api-Key": os.environ["XITROO_API_KEY"]}
address = "my-test-42@xitroo.com"
since = int(time.time())
# ... sign up with address in your app ...
while True:
time.sleep(2)
data = requests.get(f"{API}/mails", headers=HEADERS, params={
"mailAddress": address, "mailsPerPage": 10, "locale": "en",
"minTimestamp": since, "maxTimestamp": int(time.time()) + 60}).json()
if data.get("mails"):
break
mail_id = data["mails"][0]["_id"]
mail = requests.get(f"{API}/mail", headers=HEADERS,
params={"id": mail_id, "locale": "en"}).json()
print(mail["subject"])
require "net/http"
require "json"
API = "https://api.xitroo.com/v1"
def get(path, params)
uri = URI("#{API}#{path}")
uri.query = URI.encode_www_form(params)
req = Net::HTTP::Get.new(uri)
req["X-Api-Key"] = ENV.fetch("XITROO_API_KEY")
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https") { |http| http.request(req) }
JSON.parse(res.body)
end
address = "my-test-42@xitroo.com"
since = Time.now.to_i
# ... sign up with address in your app ...
list = {}
until list["mails"]
sleep 2
list = get("/mails", mailAddress: address, mailsPerPage: 10, locale: "en",
minTimestamp: since, maxTimestamp: Time.now.to_i + 60)
end
mail = get("/mail", id: list["mails"][0]["_id"], locale: "en")
puts mail["subject"]
package main
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"os"
"strconv"
"time"
)
const api = "https://api.xitroo.com/v1"
func get(path string, params url.Values, out any) error {
req, _ := http.NewRequest("GET", api+path+"?"+params.Encode(), nil)
req.Header.Set("X-Api-Key", os.Getenv("XITROO_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
return json.NewDecoder(res.Body).Decode(out)
}
func main() {
address := "my-test-42@xitroo.com"
since := time.Now().Unix()
// ... sign up with address in your app ...
var list struct {
Mails []struct {
ID string `json:"_id"`
} `json:"mails"`
}
for len(list.Mails) == 0 {
time.Sleep(2 * time.Second)
get("/mails", url.Values{
"mailAddress": {address}, "mailsPerPage": {"10"}, "locale": {"en"},
"minTimestamp": {strconv.FormatInt(since, 10)},
"maxTimestamp": {strconv.FormatInt(time.Now().Unix()+60, 10)},
}, &list)
}
var mail struct {
Subject string `json:"subject"`
}
get("/mail", url.Values{"id": {list.Mails[0].ID}, "locale": {"en"}}, &mail)
fmt.Println(mail.Subject)
}
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class WaitForMail {
static final String API = "https://api.xitroo.com/v1";
static final HttpClient HTTP = HttpClient.newHttpClient();
static String get(String pathAndQuery) throws Exception {
HttpRequest req = HttpRequest.newBuilder(URI.create(API + pathAndQuery))
.header("X-Api-Key", System.getenv("XITROO_API_KEY")).build();
return HTTP.send(req, HttpResponse.BodyHandlers.ofString()).body();
}
public static void main(String[] args) throws Exception {
String address = URLEncoder.encode("my-test-42@xitroo.com", StandardCharsets.UTF_8);
long since = System.currentTimeMillis() / 1000;
// ... sign up with the address in your app ...
Matcher id;
do {
Thread.sleep(2000);
long until = System.currentTimeMillis() / 1000 + 60;
String list = get("/mails?mailAddress=" + address + "&mailsPerPage=10&locale=en"
+ "&minTimestamp=" + since + "&maxTimestamp=" + until);
id = Pattern.compile("\"_id\":\"([0-9a-f]{24})\"").matcher(list);
} while (!id.find());
// JSON with subject, bodyText, bodyHtml, ... (parse it with your JSON library)
System.out.println(get("/mail?id=" + id.group(1) + "&locale=en"));
}
}
// .NET 6+ (dotnet new console), Program.cs
using System.Net.Http.Json;
using System.Text.Json;
var api = "https://api.xitroo.com/v1";
using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-Api-Key", Environment.GetEnvironmentVariable("XITROO_API_KEY"));
var address = Uri.EscapeDataString("my-test-42@xitroo.com");
var since = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
// ... sign up with the address in your app ...
JsonElement mails;
while (true)
{
await Task.Delay(2000);
var until = DateTimeOffset.UtcNow.ToUnixTimeSeconds() + 60;
var list = await http.GetFromJsonAsync<JsonElement>(
$"{api}/mails?mailAddress={address}&mailsPerPage=10&locale=en&minTimestamp={since}&maxTimestamp={until}");
if (list.TryGetProperty("mails", out mails)) break;
}
var id = mails[0].GetProperty("_id").GetString();
var mail = await http.GetFromJsonAsync<JsonElement>($"{api}/mail?id={id}&locale=en");
Console.WriteLine(mail.GetProperty("subject").GetString());
curl -X POST https://api.xitroo.com/v1/mail/send/premium \
-H "X-Api-Key: $XITROO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "my-test-42@xitroo.com",
"recipient": "you@example.com",
"subject": "Hello",
"bodyText": "Sent with the Xitroo API"
}'
# reply: add "replyMailID": "<_id of a received mail>"
<?php
$ctx = stream_context_create(['http' => [
'method' => 'POST',
'header' => "Content-Type: application/json\r\n"
. 'X-Api-Key: ' . getenv('XITROO_API_KEY'),
'content' => json_encode([
'from' => 'my-test-42@xitroo.com',
'recipient' => 'you@example.com',
'subject' => 'Hello',
'bodyText' => 'Sent with the Xitroo API',
// 'replyMailID' => '<_id of a received mail>',
]),
'ignore_errors' => true,
]]);
echo file_get_contents('https://api.xitroo.com/v1/mail/send/premium', false, $ctx), PHP_EOL;
// Node.js 18+, save as send.mjs
const res = await fetch("https://api.xitroo.com/v1/mail/send/premium", {
method: "POST",
headers: {
"X-Api-Key": process.env.XITROO_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
from: "my-test-42@xitroo.com",
recipient: "you@example.com",
subject: "Hello",
bodyText: "Sent with the Xitroo API",
// replyMailID: "<_id of a received mail>",
}),
});
console.log(res.status, await res.json());
import os, requests
r = requests.post(
"https://api.xitroo.com/v1/mail/send/premium",
headers={"X-Api-Key": os.environ["XITROO_API_KEY"]},
json={
"from": "my-test-42@xitroo.com",
"recipient": "you@example.com",
"subject": "Hello",
"bodyText": "Sent with the Xitroo API",
# "replyMailID": "<_id of a received mail>",
},
)
print(r.status_code, r.json())
require "net/http"
require "json"
uri = URI("https://api.xitroo.com/v1/mail/send/premium")
req = Net::HTTP::Post.new(uri, "Content-Type" => "application/json",
"X-Api-Key" => ENV.fetch("XITROO_API_KEY"))
req.body = {
from: "my-test-42@xitroo.com",
recipient: "you@example.com",
subject: "Hello",
bodyText: "Sent with the Xitroo API"
# replyMailID: "<_id of a received mail>"
}.to_json
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https") { |http| http.request(req) }
puts res.code, res.body
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
)
func main() {
body, _ := json.Marshal(map[string]string{
"from": "my-test-42@xitroo.com",
"recipient": "you@example.com",
"subject": "Hello",
"bodyText": "Sent with the Xitroo API",
// "replyMailID": "<_id of a received mail>",
})
req, _ := http.NewRequest("POST", "https://api.xitroo.com/v1/mail/send/premium", bytes.NewReader(body))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Api-Key", os.Getenv("XITROO_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
out, _ := io.ReadAll(res.Body)
fmt.Println(res.Status, string(out))
}
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class SendMail {
public static void main(String[] args) throws Exception {
String json = """
{"from": "my-test-42@xitroo.com", "recipient": "you@example.com",
"subject": "Hello", "bodyText": "Sent with the Xitroo API"}""";
HttpRequest req = HttpRequest.newBuilder(URI.create("https://api.xitroo.com/v1/mail/send/premium"))
.header("Content-Type", "application/json")
.header("X-Api-Key", System.getenv("XITROO_API_KEY"))
.POST(HttpRequest.BodyPublishers.ofString(json))
.build();
HttpResponse<String> res = HttpClient.newHttpClient().send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(res.statusCode() + " " + res.body());
}
}
// .NET 6+ (dotnet new console), Program.cs
using System.Net.Http.Json;
using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-Api-Key", Environment.GetEnvironmentVariable("XITROO_API_KEY"));
var res = await http.PostAsJsonAsync("https://api.xitroo.com/v1/mail/send/premium", new
{
@from = "my-test-42@xitroo.com",
recipient = "you@example.com",
subject = "Hello",
bodyText = "Sent with the Xitroo API",
// replyMailID = "<_id of a received mail>",
});
Console.WriteLine($"{(int)res.StatusCode} {await res.Content.ReadAsStringAsync()}");
GET /v1/mails
| Parameter | Pflicht | Bedeutung |
|---|---|---|
mailAddress |
ja | Vollständige Adresse, z. B. mein-test-42@xitroo.de |
mailsPerPage |
ja | 1 – 200 |
minTimestamp |
ja | Unix-Sekunden; nur E-Mails, die danach ankamen |
maxTimestamp |
ja | Unix-Sekunden; nur E-Mails, die davor ankamen (höchstens eine Stunde in der Zukunft) |
locale |
ja | de oder en (Sprache der Fehlermeldungen) |
Antwort, neueste zuerst:
{
"totalMails": 2,
"mails": [
{ "_id": "6748f1c2a1b2c3d4e5f60718", "from": "noreply@example.com",
"subject": "Bestätige dein Konto", "arrivalTimestamp": 1793786065.12 }
]
}
Ein leeres Postfach antwortet mit HTTP 200 und {"type": "empty response", ...} statt einer Liste.
Auf eine E-Mail warten: Setz minTimestamp auf den Startzeitpunkt deines Tests, dann siehst du nur neue E-Mails.
GET /v1/mail?id=<_id>&locale=de
Liefert deliveredTo, from, subject, arrivalTimestamp, expireTimestamp, bodyText, bodyHtml, rawHeader, messageID und attachments (Dateinamen).
GET /v1/mail/attachment?id=<_id>&filename=<name>&locale=de liefert die Datei.
POST /v1/mail/send/premium mit Kopfzeile X-Api-Key und JSON-Körper:
| Feld | Pflicht | Bedeutung |
|---|---|---|
from |
ja | Deine Absenderadresse, muss auf @xitroo.de, @xitroo.com oder @xitroo.fr enden |
recipient |
ja | Genau eine Empfängeradresse |
subject |
ja | Bis 200 Zeichen, ohne Zeilenumbruch |
bodyText |
ja | Text, bis 100 KB |
replyMailID |
nein | _id einer empfangenen E-Mail: deine E-Mail geht als Antwort darauf |
curl -X POST https://api.xitroo.com/v1/mail/send/premium \
-H "X-Api-Key: $XITROO_API_KEY" -H "Content-Type: application/json" \
-d '{"from":"mein-test-42@xitroo.de","recipient":"support@example.com","subject":"Hallo","bodyText":"Hallo zusammen!"}'
{ "sendSuccess": true, "sendsPerMonth": 1000, "sentThisMonth": 17 }
Antworten an deine Xitroo-Adresse landen in ihrem Postfach wie jede andere E-Mail. Das Monatskontingent beginnt am 1. jedes Monats (UTC) neu; höchstens 10 E-Mails pro Minute.
| HTTP | code |
Bedeutung |
|---|---|---|
| 400 | PARAMETER_INVALID, PARAMETER_REQUIRED |
Ein Parameter fehlt oder ist ungültig; siehe Feld parameter |
| 401 | INVALID_API_KEY |
Schlüssel fehlt, ist falsch oder das Abo ist nicht aktiv |
| 429 | RATE_LIMITED |
Zu viele Anfragen; Retry-After Sekunden warten |
| 429 | QUOTA_EXCEEDED |
Monatskontingent für den Versand aufgebraucht |
| 502 | SEND_FAILED |
Der Mailserver hat die E-Mail nicht angenommen; zählt nicht zum Kontingent |
Jeder Fehler ist JSON: {"status": 429, "code": "RATE_LIMITED", "message": "...", "retryAfter": 12}.
Halte deinen Schlüssel geheim: nur auf Servern oder in der CI verwenden, nie in einer öffentlichen Webseite oder App.
Abos laufen monatlich und werden von Stripe in US-Dollar abgerechnet; die Rechnung kommt jeden Monat per E-Mail. Tarif wechseln, Karte ändern, Rechnungen herunterladen oder kündigen kannst du jederzeit im Kundenportal (siehe Abo verwalten oben). Nach der Kündigung gilt dein Schlüssel bis zum Ende des bezahlten Zeitraums.