Capítulo 14 Clientes, groupware & CLI Admin: #pApiAuth

Referência completa de campos da API & CLI: todos os 12 tipos de objeto, endpoints REST & POST /api/v1/send

Esta referência documenta cada propriedade JSON, tipo de dado, valor de enum, configuração padrão e função RBAC mínima de todos os 12 objetos de gerenciamento (/api/admin/cli/objects/{type} & nextxch-cli), bem como o envio de e-mails transacionais (POST /api/v1/send). Use a caixa de filtro instantâneo acima da tabela para pesquisar qualquer propriedade, como dkimSigningMode, tlsMode, allowedCidrs ou warmingEnabled.

Dica operacional & nota de arquitetura

Introspecção ao vivo no seu terminal ou via HTTP: cada nextxch expõe este schema completo em JSON legível por máquina em GET /api/admin/cli/schema (com o cabeçalho SHA-256 X-Nextxch-Schema-Version). No terminal, execute nextxch-cli describe <Type> (por exemplo, nextxch-cli describe Domain ou nextxch-cli describe SmtpQueue) a qualquer momento.

Entrega transacional

TransactionalSendRequest (POST /api/v1/send)

Chave: Idempotency-Key RBAC: User+
13 propriedades

Endpoint HTTP JSON de entrega de alto throughput para aplicações web, ERPs, CRMs e códigos 2FA, com priorização por categoria, aquecimento de IP, verificação prévia de supressão e idempotência de 24 h.

POST /api/v1/send Enfileira e assina e-mails transacionais (UTF-8 Multipart/Alternative + anexos)
POST /api/v1/unsubscribe/{token} Endpoint público de cancelamento de inscrição com um clique (RFC 8058) (token assinado com DKIM)
{ } Esquema de objetos e propriedades tipadas application/json · camelCase
├─ from string OPCIONAL
Padrão: Key senderAddress
Endereço do remetente. Para chaves Role=User, assume automaticamente o senderAddress vinculado à chave.
├─ to string[] OBRIGATÓRIO
Array de endereços de e-mail dos destinatários principais (pelo menos 1 obrigatório).
├─ cc string[] OPCIONAL
Padrão: []
Destinatários opcionais em cópia (CC).
├─ bcc string[] OPCIONAL
Padrão: []
Destinatários opcionais em cópia oculta.
├─ replyTo string OPCIONAL
Endereço Reply-To opcional.
├─ subject string OBRIGATÓRIO
Linha de assunto do e-mail (UTF-8).
├─ textBody string OPCIONAL
Corpo em texto simples (text/plain). É obrigatório pelo menos um entre textBody e htmlBody.
├─ htmlBody string OPCIONAL
Corpo HTML (text/html). Forneça junto com textBody para entregabilidade 10/10.
├─ category string OPCIONAL
Padrão: transactional
Seleciona a prioridade na fila, o bypass do aquecimento de IP e o bucket de cota do provedor do destinatário.
Enum:"critical""transactional""notification""marketing"
├─ overflowMode string OPCIONAL
Padrão: DeferQueue
Comportamento quando a cota horária do provedor de destino é atingida (cadência suave da fila vs. HTTP 429 + Retry-After).
Enum:"DeferQueue""Reject429"
├─ idempotencyKey string OPCIONAL
Padrão: Header Idempotency-Key
Chave de deduplicação determinística (por exemplo, ID da fatura) que impede envios duplicados em 24 horas.
├─ headers Record<string, string> OPCIONAL
Padrão: {}
Dicionário de cabeçalhos X personalizados (RFC 5322).
├─ attachments SendAttachmentDto[] OPCIONAL
Padrão: []
Array de { fileName: string, contentType: string, base64Content: string }.
{
  "from": "Abrechnung <rechnung@firma.de>",
  "to": ["einkauf@kunde.de"],
  "cc": ["buchhaltung@firma.de"],
  "subject": "Ihre elektronische Rechnung RE-2026-90412",
  "category": "transactional",
  "overflowMode": "DeferQueue",
  "textBody": "Guten Tag,\nanbei erhalten Sie Ihre Rechnung RE-2026-90412.",
  "htmlBody": "<p>Guten Tag,</p><p>anbei erhalten Sie Ihre Rechnung <strong>RE-2026-90412</strong>.</p>",
  "headers": {
    "X-ERP-Document-Id": "RE-2026-90412"
  },
  "attachments": [
    {
      "fileName": "RE-2026-90412.pdf",
      "contentType": "application/pdf",
      "base64Content": "JVBERi0xLjcKJcfs..."
    }
  ]
}
# 1) Kleinstprivilegierten Sende-Key (Role=User) für rechnung@firma.de erstellen:
nextxch-cli create ApiKey \
  --set label="ERP Rechnungsversand" \
  --set role=User \
  --set senderAddress=rechnung@firma.de \
  --set defaultCategory=transactional \
  --set allowedCidrs=10.20.0.0/16

# 2) Risikofreier Trockentest gegen die integrierte Sandbox-Sink-Domain:
# ok@sink.nextxch.local | bounce@sink.nextxch.local | defer@sink.nextxch.local
curl -fsS -X POST "https://mail.firma.de/api/v1/send" \
  -H "Authorization: Bearer smk_01968f2a_..." \
  -H "Idempotency-Key: inv-2026-90412" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "rechnung@firma.de",
    "to": ["einkauf@kunde.de"],
    "subject": "Ihre Rechnung RE-2026-90412",
    "category": "transactional",
    "textBody": "Guten Tag, anbei Ihre Rechnung RE-2026-90412.",
    "htmlBody": "<p>Guten Tag, anbei Ihre Rechnung <b>RE-2026-90412</b>.</p>"
  }'
using System.Net.Http.Headers;
using System.Net.Http.Json;

using var http = new HttpClient { BaseAddress = new Uri("https://mail.firma.de") };
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "smk_01968f2a_...");
http.DefaultRequestHeaders.Add("Idempotency-Key", "inv-2026-90412");

var response = await http.PostAsJsonAsync("/api/v1/send", new
{
    from = "rechnung@firma.de",
    to = new[] { "einkauf@kunde.de" },
    subject = "Ihre Rechnung RE-2026-90412",
    category = "transactional",
    textBody = "Guten Tag, anbei Ihre Rechnung RE-2026-90412.",
    htmlBody = "<p>Guten Tag, anbei Ihre Rechnung <strong>RE-2026-90412</strong>.</p>"
});
response.EnsureSuccessStatusCode();
Objeto Collection (CRUD)

IntegrationKey (API v1)

Chave: id RBAC: TenantAdmin+
9 propriedades

Chave de integração com escopos para /api/v1. Uma chave atua em nome de um usuário ou, como integração de locatário, em nome do usuário indicado no cabeçalho X-Nextxch-Act-As. Sem o escopo, a API responde 403; um usuário de outro locatário resulta em 404. Client credentials OAuth 2.0 opcionais (token válido por 1 hora).

POST /api/admin/integrations/keys Criar uma chave (admin, exibida uma vez)
PUT /api/admin/integrations/keys/{id} Alterar escopos
DELETE /api/admin/integrations/keys/{id} Revogar uma chave (e seus tokens OAuth)
POST /api/v1/oauth/token OAuth 2.0 client_credentials: ID da chave + chave para um token de acesso
GET /api/v1/me Chave, escopos e usuário atuante
GET /api/v1/openapi.json Documento OpenAPI 3.1 da instalação
{ } Esquema de objetos e propriedades tipadas application/json · camelCase
├─ label string OBRIGATÓRIO
Rótulo, por exemplo, CRM ou ERP.
├─ mode string OBRIGATÓRIO
Padrão: user
user: sempre atua em nome de userEmail. tenant: atua em nome de X-Nextxch-Act-As (somente usuários do próprio locatário).
Enum:"user""tenant"
├─ userEmail string OPCIONAL
Usuário para mode=user.
├─ scopes string[] OBRIGATÓRIO
Permissões; .write inclui .read. crypto.read e crypto.manage (S/MIME, PGP) são reservados.
Enum:"calendar.read""calendar.write""rooms.read""booking.read""booking.write""contacts.read""contacts.write""directory.read""sharing.manage""webhooks.manage""mail.send"
├─ domainId guid OPCIONAL
Integração do locatário limitada aos usuários deste domínio.
├─ allowedCidrs string[] OPCIONAL
Padrão: []
Redes IP permitidas.
├─ expiresInDays integer OPCIONAL
Validade em dias (vazio: ilimitado).
├─ senderAddress string OPCIONAL
Remetente para mail.send (POST /api/v1/send).
├─ apiKey string SOMENTE LEITURA
smk_<id>_<secret>, somente na resposta de criação; apenas o hash é armazenado.
{
  "label": "CRM",
  "mode": "tenant",
  "scopes": ["calendar.write", "rooms.read", "contacts.write", "webhooks.manage"],
  "allowedCidrs": ["203.0.113.0/24"],
  "expiresInDays": 365
}
# Integrations-Schlüssel: Admin > API & Integrationen > Neuer Schlüssel
# Danach z. B. ein Access-Token per OAuth 2.0 Client Credentials holen:
curl -fsS -X POST "https://mail.firma.de/api/v1/oauth/token" \
  -d grant_type=client_credentials \
  -d client_id=0196c3a2-5f1e-7c11-9a20-1c2d3e4f5a6b \
  -d client_secret=smk_0196c3a25f1e7c119a201c2d3e4f5a6b_... \
  -d scope="calendar.read rooms.read"
curl -fsS "https://mail.firma.de/api/v1/me" \
  -H "Authorization: Bearer smk_0196c3a2..." \
  -H "X-Nextxch-Act-As: anna@firma.de"
using var http = new HttpClient { BaseAddress = new Uri("https://mail.firma.de") };
http.DefaultRequestHeaders.Authorization = new("Bearer", "smk_0196c3a2...");
http.DefaultRequestHeaders.Add("X-Nextxch-Act-As", "anna@firma.de");
var me = await http.GetFromJsonAsync<JsonElement>("/api/v1/me");
Objeto Collection (CRUD)

CalendarEvent (API v1)

Chave: hrefName RBAC: User+
12 propriedades

Eventos com séries e exceções, participantes, salas, convites, respostas, disponível/ocupado, calendários compartilhados e globais e links de convite. Escopos calendar.read e calendar.write. Horários em UTC (ISO-8601), fusos horários como nomes IANA.

GET /api/v1/calendars Calendários próprios, compartilhados, globais e de recursos
GET /api/v1/calendar/events?from&to&calendarId&limit&cursor Ocorrências em uma janela (séries expandidas)
POST /api/v1/calendar/events Criar um evento (convidar pessoas e salas)
GET /api/v1/calendar/events/{hrefName} Evento com séries e exceções
PUT /api/v1/calendar/events/{hrefName} Alteração; scope=occurrence|following para partes de uma série
DELETE /api/v1/calendar/events/{hrefName} Excluir, opcionalmente com cancelamentos (notify=true)
POST /api/v1/calendar/events/{hrefName}/respond Responder a um convite
POST /api/v1/calendar/events/{hrefName}/invite-link Link de convite assinado
GET /api/v1/calendar/events/{hrefName}/ics iCalendar bruto
POST /api/v1/calendar/freebusy Disponível/ocupado de pessoas e salas
{ } Esquema de objetos e propriedades tipadas application/json · camelCase
├─ title string OBRIGATÓRIO
Título.
├─ startUtc datetime OBRIGATÓRIO
Início em UTC.
├─ endUtc datetime OBRIGATÓRIO
Fim em UTC.
├─ timeZone string OPCIONAL
Padrão: Europe/Berlin
Fuso horário IANA do evento (série, exibição).
├─ allDay boolean OPCIONAL
Padrão: false
Dia inteiro.
├─ attendees Attendee[] OPCIONAL
Padrão: []
{ email, name, role }; salas e recursos aceitam ou recusam conforme suas regras.
├─ sendInvitations boolean OPCIONAL
Padrão: false
Enviar convites iMIP.
├─ recurrence Recorrência OPCIONAL
{ freq, interval, byDay, byMonthDay, count, until }.
├─ showAs string OPCIONAL
Padrão: busy
Mostrar como.
Enum:"free""tentative""busy""oof""workingElsewhere"
├─ isPrivate boolean OPCIONAL
Padrão: false
Privado (detalhes somente para o proprietário).
├─ calendarId string OPCIONAL
Calendário de destino ownerId:slug com direitos de escrita.
├─ teamsMeeting boolean OPCIONAL
Criar uma reunião do Microsoft Teams.
{
  "title": "Projektstart",
  "startUtc": "2026-12-03T09:00:00Z",
  "endUtc": "2026-12-03T10:00:00Z",
  "timeZone": "Europe/Berlin",
  "attendees": [
    { "email": "bernd@firma.de" },
    { "email": "raum-1@firma.de" }
  ],
  "sendInvitations": true
}
# Benötigte Scopes: calendar.read (lesen), calendar.write (schreiben)
# Einen Raum buchen: Raumadresse als Teilnehmer eintragen
curl -fsS -X POST "https://mail.firma.de/api/v1/calendar/events" \
  -H "Authorization: Bearer smk_0196c3a2..." \
  -H "X-Nextxch-Act-As: anna@firma.de" \
  -H "Content-Type: application/json" \
  -d '{"title":"Projektstart","startUtc":"2026-12-03T09:00:00Z","endUtc":"2026-12-03T10:00:00Z","timeZone":"Europe/Berlin","attendees":[{"email":"raum-1@firma.de"}]}'
var res = await http.PostAsJsonAsync("/api/v1/calendar/events", new
{
    title = "Projektstart",
    startUtc = DateTimeOffset.Parse("2026-12-03T09:00:00Z"),
    endUtc = DateTimeOffset.Parse("2026-12-03T10:00:00Z"),
    timeZone = "Europe/Berlin",
    attendees = new[] { new { email = "raum-1@firma.de" } }
});
string href = (await res.Content.ReadFromJsonAsync<JsonElement>()).GetProperty("data").GetProperty("hrefName").GetString()!;
Objeto Collection (CRUD)

Rooms & Booking (API v1)

Chave: id RBAC: User+
6 propriedades

Salas e recursos com disponibilidade (rooms.read) e páginas de agendamento como o Calendly (booking.read, booking.write): página de agendamento, tipos de evento, horários livres, leitura e cancelamento de agendamentos. Uma sala é reservada por meio de um evento que tem a sala como participante.

GET /api/v1/rooms?startUtc&endUtc&category Salas e recursos, com disponibilidade para a janela
GET /api/v1/rooms/{email}/availability Horários ocupados de uma sala
GET /api/v1/booking/profile Página de agendamento com horários e tipos de evento
GET /api/v1/booking/event-types Tipos de evento
POST /api/v1/booking/event-types Criar um tipo de evento
GET /api/v1/booking/event-types/{id}/slots?from&to Horários de início livres (máx. 42 dias)
GET /api/v1/booking/bookings?status&from&to Reservas
POST /api/v1/booking/bookings/{id}/cancel Cancelar um agendamento (o convidado é informado)
{ } Esquema de objetos e propriedades tipadas application/json · camelCase
├─ slots[].startUtc datetime SOMENTE LEITURA
Início livre em UTC.
├─ slots[].endUtc datetime SOMENTE LEITURA
Fim (início mais duração).
├─ slots[].staff object[] SOMENTE LEITURA
Liberar equipe para tipos de evento de equipe.
├─ status string SOMENTE LEITURA
Status da reserva.
Enum:"confirmed""cancelled"
├─ guest object SOMENTE LEITURA
{ name, email, phone, timeZone }.
├─ free boolean SOMENTE LEITURA
Sala livre no intervalo.
{
  "ok": true,
  "data": {
    "eventTypeId": "beratung-3f2a",
    "durationMinutes": 30,
    "timeZone": "Europe/Berlin",
    "slots": [
      { "startUtc": "2026-12-04T08:00:00Z", "endUtc": "2026-12-04T08:30:00Z", "staff": [] }
    ]
  }
}
# Benötigte Scopes: rooms.read, booking.read, booking.write
curl -fsS "https://mail.firma.de/api/v1/rooms?startUtc=2026-12-03T09:00:00Z&endUtc=2026-12-03T10:00:00Z" \
  -H "Authorization: Bearer smk_0196c3a2..."
var slots = await http.GetFromJsonAsync<JsonElement>("/api/v1/booking/event-types/beratung/slots");
foreach (var s in slots.GetProperty("data").GetProperty("slots").EnumerateArray())
    Console.WriteLine(s.GetProperty("startUtc").GetString());
Objeto Collection (CRUD)

Contact, Directory & Sharing (API v1)

Chave: hrefName RBAC: User+
9 propriedades

Contatos pessoais com todos os campos e foto (contacts.read, contacts.write, If-Match para proteção contra conflitos), lista de endereços global (directory.read) e compartilhamentos e delegação (sharing.manage, delegação = permissão na caixa de correio com sendAs ou sendOnBehalf).

GET /api/v1/contacts?q Pesquisar contatos
POST /api/v1/contacts Criar um contato
PUT /api/v1/contacts/{hrefName} Alterar um contato (campos nulos permanecem)
DELETE /api/v1/contacts/{hrefName} Excluir um contato
GET /api/v1/directory?q&type Lista de endereços global
GET /api/v1/sharing/grants Permissões próprias
PUT /api/v1/sharing/grants Definir ou remover uma permissão
GET /api/v1/sharing/shared-with-me Compartilhado comigo
{ } Esquema de objetos e propriedades tipadas application/json · camelCase
├─ givenName string OPCIONAL
Nome.
├─ familyName string OPCIONAL
Sobrenome.
├─ organization string OPCIONAL
Empresa.
├─ emails TypedValue[] OPCIONAL
Padrão: []
{ type: work|home|other, value }.
├─ phones TypedValue[] OPCIONAL
Padrão: []
{ type: cell|work|home|fax, value }.
├─ addresses Address[] OPCIONAL
Padrão: []
{ type, street, city, region, postalCode, country }.
├─ birthday string OPCIONAL
yyyy-MM-dd ou --MM-dd.
├─ photo string SOMENTE ESCRITA (SEGREDO)
data:image/jpeg;base64,... (máx. 512 KB), vazio remove.
├─ permissions string[] OPCIONAL
Direitos de uma concessão (PUT /sharing/grants).
Enum:"freeBusy""read""write""delete""sendOnBehalf""sendAs""manage"
{
  "givenName": "Clara",
  "familyName": "Kunde",
  "organization": "Kunde AG",
  "emails": [{ "type": "work", "value": "clara@kunde.example" }],
  "phones": [{ "type": "cell", "value": "+49 170 1234567" }]
}
# Benötigte Scopes: contacts.read, contacts.write, directory.read, sharing.manage
curl -fsS -X POST "https://mail.firma.de/api/v1/contacts" \
  -H "Authorization: Bearer smk_0196c3a2..." \
  -H "Content-Type: application/json" \
  -d '{"givenName":"Clara","familyName":"Kunde","emails":[{"type":"work","value":"clara@kunde.example"}]}'
await http.PutAsJsonAsync("/api/v1/sharing/grants", new
{
    kind = "calendar", granteeType = "user", grantee = "bernd@firma.de", permissions = new[] { "read" }
});
Objeto Collection (CRUD)

Webhook (API v1)

Chave: id RBAC: User+
4 propriedades

Eventos como JSON POST assinado: calendar.event.created, calendar.event.updated, calendar.event.deleted, calendar.invitation.replied, booking.created, booking.rescheduled, booking.cancelled. Assinatura X-Nextxch-Signature: v1=hex(HMAC-SHA256(secret, X-Nextxch-Timestamp + "." + body)). Novas tentativas após 30 s, 2 min, 10 min, 1 h e 6 h.

GET /api/v1/webhooks Webhooks do locatário
POST /api/v1/webhooks Registrar um webhook (segredo somente na resposta)
DELETE /api/v1/webhooks/{id} Excluir um webhook
GET /api/v1/webhooks/{id}/deliveries Entregas recentes
POST /api/v1/webhooks/{id}/test Enviar um evento de teste
{ } Esquema de objetos e propriedades tipadas application/json · camelCase
├─ url string OBRIGATÓRIO
Destino HTTPS (endereços internos são bloqueados).
├─ events string[] OBRIGATÓRIO
Eventos; a chave precisa dos escopos .read correspondentes.
Enum:"calendar.event.created""calendar.event.updated""calendar.event.deleted""calendar.invitation.replied""booking.created""booking.rescheduled""booking.cancelled""*"
├─ secret string SOMENTE LEITURA
whsec_..., somente na criação; armazenado criptografado.
├─ id (Ereignis) string SOMENTE LEITURA
evt_... estável por alteração, para deduplicação.
{
  "id": "evt_5c1f0e9a2b7d4c3e8f601a2b",
  "type": "calendar.invitation.replied",
  "createdAtUtc": "2026-12-01T10:15:02Z",
  "tenantId": "0196c3a2-0000-7000-8000-000000000001",
  "data": {
    "calendarId": "0196c3a25f1e7c11:default",
    "hrefName": "0196c3a2@nextxch.ics",
    "title": "Projektstart",
    "startUtc": "2026-12-03T09:00:00Z",
    "attendee": { "email": "bernd@firma.de", "partStat": "ACCEPTED" }
  }
}
# Signatur prüfen (Bash):
# expected="v1=$(printf '%s.%s' "$TS" "$BODY" | openssl dgst -sha256 -hmac "$SECRET" | cut -d' ' -f2)"
curl -fsS -X POST "https://mail.firma.de/api/v1/webhooks" \
  -H "Authorization: Bearer smk_0196c3a2..." \
  -H "Content-Type: application/json" \
  -d '{"url":"https://crm.firma.de/hooks/nextxch","events":["calendar.event.created","booking.created"]}'
// ASP.NET Core receiver
app.MapPost("/hooks/nextxch", async (HttpRequest req) =>
{
    using var ms = new MemoryStream();
    await req.Body.CopyToAsync(ms);
    string ts = req.Headers["X-Nextxch-Timestamp"]!;
    byte[] mac = HMACSHA256.HashData(Encoding.UTF8.GetBytes(secret), [.. Encoding.ASCII.GetBytes(ts + "."), .. ms.ToArray()]);
    return req.Headers["X-Nextxch-Signature"] == "v1=" + Convert.ToHexStringLower(mac) ? Results.Ok() : Results.Unauthorized();
});
Objeto Collection (CRUD)

Tenant

Chave: slug RBAC: ServerAdmin+
11 propriedades

Limite organizacional multilocatário que isola domínios, principais, cotas de armazenamento (GiB) e a retenção de conformidade GoBD WORM padrão.

GET /api/admin/cli/objects/Tenant Lista todos os locatários
GET /api/admin/cli/objects/Tenant/{slugOrId} Obtém o locatário por slug ou UUID
POST /api/admin/cli/objects/Tenant Cria um novo locatário
PATCH /api/admin/cli/objects/Tenant/{slugOrId} Atualiza as cotas do locatário no local
{ } Esquema de objetos e propriedades tipadas application/json · camelCase
├─ id guid SOMENTE LEITURA
Padrão: UUIDv7
Identificador interno imutável UUIDv7.
├─ slug string PRIMARY KEY
Chave de locatário única e segura para URL (por exemplo, "default", "acme").
├─ name string OBRIGATÓRIO
Nome de exibição legível da organização.
├─ isActive boolean OPCIONAL
Padrão: true
Ativar ou suspender o locatário.
├─ maxDomains integer OPCIONAL
Padrão: 100
Máximo de domínios permitidos neste locatário.
├─ maxPrincipals integer OPCIONAL
Padrão: 10000
Máximo de contas e listas de distribuição.
├─ quotaGb integer OPCIONAL
Padrão: 100
Limite de armazenamento do locatário em GiB.
├─ outboundDailyLimit integer OPCIONAL
Padrão: 25000
Máximo de e-mails de saída por dia em todo o locatário.
├─ defaultLockMode string OPCIONAL
Padrão: Normal
Modo de bloqueio GoBD WORM padrão para domínios recém-criados.
Enum:"Normal""Governance""Compliance""LegalHold"
├─ defaultRetentionDays integer OPCIONAL
Padrão: 0
Período padrão de retenção obrigatória em dias (3650 = 10 anos GoBD).
├─ createdAtUtc datetime SOMENTE LEITURA
Data e hora de criação em UTC.
{
  "slug": "acme",
  "name": "ACME Logistik GmbH",
  "isActive": true,
  "maxDomains": 50,
  "maxPrincipals": 2500,
  "quotaGb": 250,
  "outboundDailyLimit": 25000,
  "defaultLockMode": "Compliance",
  "defaultRetentionDays": 3650
}
# Mandant anlegen:
nextxch-cli create Tenant \
  --set slug=acme \
  --set name="ACME Logistik GmbH" \
  --set quotaGb=250 \
  --set defaultLockMode=Compliance \
  --set defaultRetentionDays=3650

# Mandant abfragen & Kontingent erhöhen:
nextxch-cli get Tenant acme
nextxch-cli update Tenant acme --set quotaGb=500
curl -fsS -X POST "https://mail.firma.de/api/admin/cli/objects/Tenant" \
  -H "Authorization: Bearer smk_..." \
  -H "Content-Type: application/json" \
  -d '{"slug":"acme","name":"ACME Logistik GmbH","quotaGb":250,"defaultLockMode":"Compliance","defaultRetentionDays":3650}'
var payload = new
{
    slug = "acme",
    name = "ACME Logistik GmbH",
    quotaGb = 250,
    defaultLockMode = "Compliance",
    defaultRetentionDays = 3650
};
using var res = await http.PostAsJsonAsync("/api/admin/cli/objects/Tenant", payload);
Objeto Collection (CRUD)

Domain

Chave: name RBAC: TenantAdmin+
19 propriedades

Domínio de e-mail hospedado com geração automática e paralela de chaves Dual-DKIM (RSA-2048 + Ed25519), política de retenção GoBD WORM, plus-addressing e limites de taxa.

GET /api/admin/cli/objects/Domain Lista todos os domínios
GET /api/admin/cli/objects/Domain/{name} Obtém a configuração do domínio & os seletores DKIM
POST /api/admin/cli/objects/Domain Cria o domínio & gera chaves DKIM RSA-2048 + Ed25519
PATCH /api/admin/cli/objects/Domain/{name} Atualiza o modo DKIM, cotas ou retenção em 0 ms
GET /api/admin/cli/dns/{name}?live=true Verifica registros DNS ao vivo ou exporta a zona BIND conforme RFC 1035
{ } Esquema de objetos e propriedades tipadas application/json · camelCase
├─ id guid SOMENTE LEITURA
Padrão: UUIDv7
UUIDv7 interno do domínio.
├─ name string PRIMARY KEY
Nome de domínio DNS (por exemplo, "muster-logistik.de").
├─ tenant string OPCIONAL
Padrão: default
Slug ou GUID do locatário proprietário.
├─ isActive boolean OPCIONAL
Padrão: true
Ativar ou pausar o domínio.
├─ postmasterAddress string OPCIONAL
Padrão: postmaster@<name>
Endereço de contato postmaster conforme RFC 5321.
├─ dkimSigningMode string OPCIONAL
Padrão: Dual
Modo de assinatura DKIM ativo (Dual assina com RSA-2048 e Ed25519).
Enum:"Rsa2048""Ed25519""Dual"
├─ dkimRsaSelector string OPCIONAL
Padrão: s2026
Seletor DNS RSA-2048.
├─ dkimRsaDnsName string SOMENTE LEITURA
Padrão: s2026._domainkey.<name>
FQDN _domainkey RSA-2048 calculado.
├─ dkimEd25519Selector string OPCIONAL
Padrão: ed2026
Seletor DNS Ed25519.
├─ dkimEd25519DnsName string SOMENTE LEITURA
Padrão: ed2026._domainkey.<name>
FQDN _domainkey Ed25519 calculado.
├─ retentionLockMode string OPCIONAL
Padrão: Normal
Modo de bloqueio do arquivo GoBD WORM para este domínio.
Enum:"Normal""Governance""Compliance""LegalHold"
├─ retentionDays integer OPCIONAL
Padrão: 0
Duração obrigatória da retenção em dias (3650 = 10 anos GoBD).
├─ quotaGb integer OPCIONAL
Padrão: 50
Limite de armazenamento do domínio em GiB.
├─ maxMessageSizeMb integer OPCIONAL
Padrão: 50
Tamanho máximo da mensagem em MiB.
├─ maxAccounts integer OPCIONAL
Padrão: 1000
Máximo de caixas de correio neste domínio.
├─ outboundDailyLimit integer OPCIONAL
Padrão: 5000
Limite diário de envio de saída para este domínio.
├─ outboundHourlyLimit integer OPCIONAL
Padrão: 1000
Limite de envio de saída por hora para este domínio.
├─ usePlusAddressing boolean OPCIONAL
Padrão: true
Ativa o plus-addressing da RFC 5233 (user+tag@domain).
├─ createdAtUtc datetime SOMENTE LEITURA
Data e hora de criação em UTC.
{
  "name": "muster-logistik.de",
  "tenant": "default",
  "isActive": true,
  "postmasterAddress": "postmaster@muster-logistik.de",
  "dkimSigningMode": "Dual",
  "dkimRsaSelector": "s2026",
  "dkimEd25519Selector": "ed2026",
  "retentionLockMode": "Compliance",
  "retentionDays": 3650,
  "quotaGb": 100,
  "maxMessageSizeMb": 50,
  "maxAccounts": 500,
  "outboundDailyLimit": 10000,
  "outboundHourlyLimit": 2000,
  "usePlusAddressing": true
}
# Domain mit Dual-DKIM und 10 Jahren GoBD-Compliance anlegen:
nextxch-cli create Domain \
  --set name=muster-logistik.de \
  --set dkimSigningMode=Dual \
  --set retentionLockMode=Compliance \
  --set retentionDays=3650

# Fertige RFC-1035 BIND-Zonendatei exportieren & DNS live prüfen:
nextxch-cli dns muster-logistik.de --bind > muster-logistik.de.zone
nextxch-cli dns muster-logistik.de --live
curl -fsS -X PATCH "https://mail.firma.de/api/admin/cli/objects/Domain/muster-logistik.de" \
  -H "Authorization: Bearer smk_..." \
  -H "Content-Type: application/json" \
  -d '{"dkimSigningMode":"Dual","retentionLockMode":"Compliance","retentionDays":3650}'
using var res = await http.PatchAsJsonAsync(
    "/api/admin/cli/objects/Domain/muster-logistik.de",
    new { dkimSigningMode = "Dual", quotaGb = 200 });
res.EnsureSuccessStatusCode();
Objeto Collection (CRUD)

Account (Account/User & Account/List)

Chave: email RBAC: TenantAdmin+
18 propriedades

Representa uma caixa de correio de usuário (@type="User", com IMAP/JMAP/CalDAV/CardDAV/ActiveSync) ou uma lista de distribuição (@type="List" com members[]).

GET /api/admin/cli/objects/Account?filter=role=TenantAdmin Lista/filtra contas e listas de distribuição
POST /api/admin/cli/objects/Account/User Cria uma nova caixa de correio de usuário com pastas RFC 6154
POST /api/admin/cli/objects/Account/List Cria uma nova lista de distribuição
PATCH /api/admin/cli/objects/Account/{email} Atualiza cota, encaminhamento, ausência ou senha
DELETE /api/admin/cli/objects/Account/{email} Exclui uma conta de forma reversível (soft delete)
{ } Esquema de objetos e propriedades tipadas application/json · camelCase
├─ id guid SOMENTE LEITURA
Padrão: UUIDv7
UUIDv7 interno do principal.
├─ @type string OPCIONAL
Padrão: User
Variante de Account: caixa de correio de usuário (User) ou grupo de distribuição (List).
Enum:"User""List"
├─ email string PRIMARY KEY
Endereço de e-mail principal da caixa de correio ou da lista.
├─ displayName string OPCIONAL
Padrão: Lokalteil
Nome de exibição mostrado no Webmail, na GAL e nos cabeçalhos From.
├─ password string SOMENTE ESCRITA (SEGREDO)
Senha em texto puro na criação/atualização (imediatamente convertida em hash com Argon2id).
├─ role string OPCIONAL
Padrão: User
Função administrativa RBAC.
Enum:"User""ComplianceAuditor""TenantAdmin""ServerAdmin"
├─ isActive boolean OPCIONAL
Padrão: true
Ativar ou suspender a conta.
├─ quotaMb integer OPCIONAL
Padrão: 5120
Cota de armazenamento da caixa de correio em MiB (5120 = 5 GiB).
├─ usedBytes long SOMENTE LEITURA
Padrão: 0
Uso atual de armazenamento da caixa de correio em bytes.
├─ outboundDailyLimit integer OPCIONAL
Padrão: 500
Limite diário de mensagens de saída para esta conta.
├─ forwardAddress string OPCIONAL
E-mail de destino opcional para encaminhamento seguro com SRS.
├─ forwardKeepOriginal boolean OPCIONAL
Padrão: true
Manter uma cópia local na INBOX quando o encaminhamento estiver ativo.
├─ vacationEnabled boolean OPCIONAL
Padrão: false
Ativa a resposta automática de ausência.
├─ vacationSubject string OPCIONAL
Assunto da resposta automática de ausência.
├─ vacationBody string SOMENTE ESCRITA (SEGREDO)
Texto do corpo da resposta automática de ausência.
├─ twoFactorEnabled boolean SOMENTE LEITURA
Padrão: false
Indica se o 2FA TOTP está ativo.
├─ members string[] OPCIONAL
Padrão: []
Endereços de e-mail dos membros (para @type="List").
├─ createdAtUtc datetime SOMENTE LEITURA
Data e hora de criação em UTC.
{
  "@type": "User",
  "email": "anna.weber@muster-logistik.de",
  "displayName": "Anna Weber (IT-Leitung)",
  "password": "SicheresStartPasswort!2026",
  "role": "TenantAdmin",
  "isActive": true,
  "quotaMb": 15360,
  "outboundDailyLimit": 1000,
  "forwardAddress": null,
  "forwardKeepOriginal": true,
  "vacationEnabled": false,
  "vacationSubject": "Abwesenheitsnotiz: Anna Weber",
  "vacationBody": "Ich bin ab Montag wieder erreichbar."
}
# Benutzerpostfach (15 GiB Quota) anlegen:
nextxch-cli create Account/User \
  --set email=anna.weber@muster-logistik.de \
  --set displayName="Anna Weber" \
  --set password="SicheresStartPasswort!2026" \
  --set quotaMb=15360

# Verteilerliste anlegen:
nextxch-cli create Account/List \
  --set email=team@muster-logistik.de \
  --set displayName="Disposition & Einkauf" \
  --set members=anna.weber@muster-logistik.de,dispo@muster-logistik.de
curl -fsS -X POST "https://mail.firma.de/api/admin/cli/objects/Account/User" \
  -H "Authorization: Bearer smk_..." \
  -H "Content-Type: application/json" \
  -d '{"email":"anna.weber@muster-logistik.de","displayName":"Anna Weber","password":"SicheresStartPasswort!2026","quotaMb":15360}'
await http.PostAsJsonAsync("/api/admin/cli/objects/Account/User", new
{
    email = "anna.weber@muster-logistik.de",
    displayName = "Anna Weber",
    password = "SicheresStartPasswort!2026",
    quotaMb = 15360
});
Objeto Collection (CRUD)

Alias

Chave: address RBAC: TenantAdmin+
7 propriedades

Alias de e-mail secundário ou alias de privacidade mascarado descartável, roteado para uma caixa de correio Account principal ou uma lista de distribuição.

GET /api/admin/cli/objects/Alias Lista todos os aliases e e-mails mascarados
POST /api/admin/cli/objects/Alias Cria um novo alias roteado para uma caixa de correio de destino
PATCH /api/admin/cli/objects/Alias/{address} Ativa/pausa um alias ou atualiza seu destino
DELETE /api/admin/cli/objects/Alias/{address} Exclui o alias
{ } Esquema de objetos e propriedades tipadas application/json · camelCase
├─ address string PRIMARY KEY
O endereço de e-mail do alias.
├─ target string OBRIGATÓRIO
Endereço de e-mail da conta primária de destino.
├─ principalId guid SOMENTE LEITURA
UUID do principal de destino resolvido.
├─ description string OPCIONAL
Padrão: ""
Nota de finalidade ou rótulo de serviço externo (também exibido no editor de mensagens do Webmail).
├─ isMasked boolean OPCIONAL
Padrão: false
Marca o alias como alias de privacidade mascarado.
├─ isEnabled boolean OPCIONAL
Padrão: true
Quando false, e-mails para este alias são rejeitados sem liberar o endereço.
├─ createdAtUtc datetime SOMENTE LEITURA
Data e hora de criação em UTC.
{
  "address": "shop-8f2k@muster-logistik.de",
  "target": "anna.weber@muster-logistik.de",
  "description": "Fachbuchhandlung / Online-Bestellung",
  "isMasked": true,
  "isEnabled": true
}
# Masked-Email-Alias anlegen:
nextxch-cli create Alias \
  --set address=shop-8f2k@muster-logistik.de \
  --set target=anna.weber@muster-logistik.de \
  --set description="Fachbuchhandlung" \
  --set isMasked=true

# Alias bei Spam-Aufkommen mit 1 Befehl stummschalten:
nextxch-cli update Alias shop-8f2k@muster-logistik.de --set isEnabled=false
curl -fsS -X POST "https://mail.firma.de/api/admin/cli/objects/Alias" \
  -H "Authorization: Bearer smk_..." \
  -H "Content-Type: application/json" \
  -d '{"address":"vertrieb@muster-logistik.de","target":"anna.weber@muster-logistik.de","description":"Vertrieb & Angebote"}'
await http.PostAsJsonAsync("/api/admin/cli/objects/Alias", new
{
    address = "vertrieb@muster-logistik.de",
    target = "anna.weber@muster-logistik.de",
    description = "Vertrieb & Angebote",
    isEnabled = true
});
Objeto Collection (CRUD)

ApiKey

Chave: id RBAC: TenantAdmin+
11 propriedades

Chave de API com escopo, imutável e restrita por RBAC e CIDR (smk_<id>_<secret>) para /api/v1/send, SCIM 2.0 ou nextxch-cli.

GET /api/admin/cli/objects/ApiKey Lista as chaves de API ativas (sem o segredo)
POST /api/admin/cli/objects/ApiKey Emite uma nova chave de API e retorna apiKey (smk_...) uma única vez
DELETE /api/admin/cli/objects/ApiKey/{id} Revoga a chave de API imediatamente
{ } Esquema de objetos e propriedades tipadas application/json · camelCase
├─ id guid SOMENTE LEITURA
Padrão: UUIDv7
UUID único da chave (usado para revogar via DELETE).
├─ apiKey string SOMENTE NA CRIAÇÃO
Padrão: smk_<id>_<secret>
Token Bearer completo retornado SOMENTE uma vez, na criação.
├─ label string OBRIGATÓRIO
Rótulo legível (por exemplo, "Ansible GitOps" ou "Shopware 6").
├─ role string OPCIONAL
Padrão: TenantAdmin
Escopo de privilégios (User fica estritamente restrito a POST /api/v1/send).
Enum:"User""ComplianceAuditor""TenantAdmin""ServerAdmin"
├─ senderAddress string OPCIONAL
Endereço de remetente autorizado (obrigatório quando role="User").
├─ defaultCategory string OPCIONAL
Padrão: transactional
Categoria de envio padrão para esta chave.
Enum:"critical""transactional""notification""marketing"
├─ allowedCidrs string[] OPCIONAL
Padrão: [] (todos os IPs)
Redes CIDR IPv4/IPv6 de origem permitidas.
├─ expiresInDays integer SOMENTE ESCRITA (SEGREDO)
Padrão: null (Kein Ablauf)
Expiração automática opcional em dias a partir da criação.
├─ expiresAtUtc datetime SOMENTE LEITURA
Carimbo de data/hora de expiração UTC calculado.
├─ outboundDailyLimit integer OPCIONAL
Padrão: 10000
Limite diário de envio de saída para esta chave.
├─ isActive boolean SOMENTE LEITURA
Padrão: true
Status ativo.
{
  "label": "Shopware 6 ERP Rechnungsversand",
  "role": "User",
  "senderAddress": "rechnung@muster-logistik.de",
  "defaultCategory": "transactional",
  "allowedCidrs": ["10.20.10.15/32", "2a01:4f8:120:44aa::/64"],
  "expiresInDays": 180,
  "outboundDailyLimit": 10000
}
# CIDR-geschützten Key für Ansible / nextxch-cli erstellen:
nextxch-cli create ApiKey \
  --set label="GitLab CI / Ansible" \
  --set role=TenantAdmin \
  --set allowedCidrs=10.20.0.0/16 \
  --set expiresInDays=90

# Schlüssel widerrufen:
nextxch-cli delete ApiKey 0195f2a0-8b14-7000-9a10-001122334455
curl -fsS -X POST "https://mail.firma.de/api/admin/cli/objects/ApiKey" \
  -H "Authorization: Bearer smk_..." \
  -H "Content-Type: application/json" \
  -d '{"label":"Shopware 6","role":"User","senderAddress":"rechnung@muster-logistik.de","allowedCidrs":["10.20.10.15/32"],"expiresInDays":180}'
var res = await http.PostAsJsonAsync("/api/admin/cli/objects/ApiKey", new
{
    label = "Shopware 6",
    role = "User",
    senderAddress = "rechnung@muster-logistik.de",
    allowedCidrs = new[] { "10.20.10.15/32" },
    expiresInDays = 180
});
var created = await res.Content.ReadFromJsonAsync<JsonElement>();
string oneTimeSecretKey = created.GetProperty("apiKey").GetString()!;
Objeto Collection (CRUD)

Route

Chave: domain RBAC: ServerAdmin+
10 propriedades

Roteamento SMTP de saída por domínio ou exceção de certificado TLS (por exemplo, StartTlsIgnoreCert para hosts MX de parceiros com certificados divergentes, ou conector de smart host).

GET /api/admin/cli/objects/Route Lista todas as rotas de saída personalizadas
POST /api/admin/cli/objects/Route Cria uma rota de domínio personalizada ou uma substituição de TLS
PATCH /api/admin/cli/objects/Route/{domain} Atualiza o host de destino, a porta ou o modo TLS
DELETE /api/admin/cli/objects/Route/{domain} Exclui a rota personalizada
{ } Esquema de objetos e propriedades tipadas application/json · camelCase
├─ domain string PRIMARY KEY
Domínio do destinatário (por exemplo, "neff.me" ou "*.partner-holding.eu").
├─ targetHost string OPCIONAL
Padrão: "" (Auto DNS-MX)
Hostname ou IP do relay. Deixe vazio para resolver automaticamente o MX de destino via DNS.
├─ targetPort integer OPCIONAL
Padrão: 25
Porta TCP de destino (25, 587 ou 465).
├─ tlsMode string OPCIONAL
Padrão: StartTlsOptional
Modo de TLS de saída e de validação X.509 para este domínio.
Enum:"StartTlsOptional""StartTlsRequired""StartTlsIgnoreCert""ImplicitTls""ImplicitTlsIgnoreCert""None"
├─ username string OPCIONAL
Nome de usuário SMTP AUTH opcional.
├─ password string SOMENTE ESCRITA (SEGREDO)
Senha SMTP AUTH opcional.
├─ hasPassword boolean SOMENTE LEITURA
Padrão: false
Indica se há uma senha armazenada.
├─ clearPassword boolean SOMENTE ESCRITA (SEGREDO)
Padrão: false
Defina como true para apagar a senha armazenada.
├─ description string OPCIONAL
Nota de auditoria do administrador.
├─ enabled boolean OPCIONAL
Padrão: true
Ativar ou pausar a rota.
{
  "domain": "neff.me",
  "targetHost": "",
  "targetPort": 25,
  "tlsMode": "StartTlsIgnoreCert",
  "username": null,
  "description": "Shared-Hosting-MX mit abweichendem Zertifikatsnamen (Auto DNS-MX)",
  "enabled": true
}
# Partner-Domain mit fehlerhaftem MX-Zertifikat per Auto-DNS-MX freigeben:
nextxch-cli create Route \
  --set domain=neff.me \
  --set tlsMode=StartTlsIgnoreCert \
  --set description="TLS NameMismatch auf Partner-MX erlauben"

# Internes ERP-Subnetz an lokalen Connector routen:
nextxch-cli create Route \
  --set domain=erp.firma.intern \
  --set targetHost=10.40.2.15 \
  --set targetPort=25
curl -fsS -X POST "https://mail.firma.de/api/admin/cli/objects/Route" \
  -H "Authorization: Bearer smk_..." \
  -H "Content-Type: application/json" \
  -d '{"domain":"neff.me","targetHost":"","targetPort":25,"tlsMode":"StartTlsIgnoreCert","enabled":true}'
await http.PostAsJsonAsync("/api/admin/cli/objects/Route", new
{
    domain = "neff.me",
    targetHost = "",
    targetPort = 25,
    tlsMode = "StartTlsIgnoreCert",
    enabled = true
});
Política singleton

TransactionalSend (Singleton)

Chave: singleton RBAC: TenantAdmin+
11 propriedades

Controla o aquecimento progressivo de IP em 28 dias, as categorias de mensagens e as cotas por hora/dia por provedor destinatário (Google, Microsoft, Yahoo/AOL, provedores alemães, iCloud, *).

GET /api/admin/cli/objects/TransactionalSend/singleton Obtém a política ativa de aquecimento de IP & cotas por provedor
PATCH /api/admin/cli/objects/TransactionalSend/singleton Atualiza o dia de aquecimento, o preset ou as cotas por provedor
{ } Esquema de objetos e propriedades tipadas application/json · camelCase
├─ enabled boolean OPCIONAL
Padrão: true
Ativa a governança de categorias e de cotas por provedor.
├─ warmingEnabled boolean OPCIONAL
Padrão: false
Ativa a rampa diária progressiva de aquecimento de IP.
├─ startAtWarmingDay integer SOMENTE ESCRITA (SEGREDO)
Padrão: 1
Salta ou redefine a agenda de aquecimento para o dia N (1..365).
├─ currentWarmingDay integer SOMENTE LEITURA
Dia ativo atual no cronograma de aquecimento.
├─ currentWarmingPercent integer SOMENTE LEITURA
Percentual ativo atual das cotas do provedor de destino.
├─ warmingDailyRampPercents integer[] OPCIONAL
Padrão: [5,7,10,...,100]
Array de percentuais diários para a rampa de aquecimento.
├─ maxDeferHours integer OPCIONAL
Padrão: 48
Janela máxima de antecipação, em horas, para o ritmo do DeferQueue.
├─ defaultCategory string OPCIONAL
Padrão: transactional
Categoria padrão quando omitida nas chamadas de API.
Enum:"critical""transactional""notification""marketing"
├─ preset string SOMENTE ESCRITA (SEGREDO)
Seletor de predefinição em uma etapa.
Enum:"warming_28d""warming_14d""production_100"
├─ categories CategoryPolicy[] OPCIONAL
Padrão: 4 Kategorien
Array de objetos de política de categoria.
├─ providers ProviderQuota[] OPCIONAL
Padrão: 6 Provider-Gruppen
Array de definições de cota por provedor do destinatário.
{
  "enabled": true,
  "warmingEnabled": true,
  "startAtWarmingDay": 1,
  "maxDeferHours": 48,
  "defaultCategory": "transactional",
  "preset": "warming_28d"
}
# 28-Tage IP-Warming aktivieren:
nextxch-cli update TransactionalSend --set preset=warming_28d

# Direkt auf Warming-Tag 14 vorspringen:
nextxch-cli update TransactionalSend --set startAtWarmingDay=14
curl -fsS -X PATCH "https://mail.firma.de/api/admin/cli/objects/TransactionalSend/singleton" \
  -H "Authorization: Bearer smk_..." \
  -H "Content-Type: application/json" \
  -d '{"preset":"warming_28d","enabled":true}'
await http.PatchAsJsonAsync(
    "/api/admin/cli/objects/TransactionalSend/singleton",
    new { preset = "warming_28d", enabled = true });
Política singleton

ReputationShield (Singleton)

Chave: singleton RBAC: TenantAdmin+
20 propriedades

Proteção opcional da reputação de saída: lista automática de supressão de bounces/reclamações, cancelamento de inscrição com um clique (RFC 8058), disjuntor de bounces, backoff adaptativo para 421 de ISPs e webhooks HMAC-SHA256.

GET /api/admin/cli/objects/ReputationShield/singleton Obtém a configuração atual do Reputation Shield
PATCH /api/admin/cli/objects/ReputationShield/singleton Atualiza as flags de proteção ou aplica uma predefinição
{ } Esquema de objetos e propriedades tipadas application/json · camelCase
├─ preset string SOMENTE ESCRITA (SEGREDO)
Aplica um perfil de proteção completo em um só passo.
Enum:"off""recommended""strict_bulk"
├─ enableSuppressionPreCheck boolean OPCIONAL
Padrão: false
Filtra endereços suprimidos antes do envio.
├─ enforceSuppressionOnSmtpRelay boolean OPCIONAL
Padrão: false
Também aplica a lista de supressão no envio SMTP (submission).
├─ allSuppressedBehavior string OPCIONAL
Padrão: reject_422
Modo de resposta quando todos os destinatários estão suprimidos.
Enum:"reject_422""accept_noop"
├─ autoSuppressHardBounces boolean OPCIONAL
Padrão: false
Suprime automaticamente hard bounces permanentes 5xx.
├─ hardBounceSuppressionDays integer OPCIONAL
Padrão: 180
Dias de retenção para supressões de hard bounce.
├─ autoSuppressConsecutiveSoftBounces boolean OPCIONAL
Padrão: false
Escala soft bounces 4xx repetidos para a lista de supressão.
├─ softBounceEscalationThreshold integer OPCIONAL
Padrão: 5
Soft bounces consecutivos antes da supressão.
├─ autoSuppressFblComplaints boolean OPCIONAL
Padrão: false
Analisa automaticamente relatórios de abuso ARF (RFC 5965) recebidos.
├─ enableOneClickUnsubscribe boolean OPCIONAL
Padrão: false
Insere cabeçalhos List-Unsubscribe RFC 8058 assinados com DKIM.
├─ oneClickUnsubscribeCategories string[] OPCIONAL
Padrão: ["marketing","notification"]
Categorias que recebem cabeçalhos de cancelamento de inscrição RFC 8058.
├─ enableBounceCircuitBreaker boolean OPCIONAL
Padrão: false
Pausa envios não críticos se a taxa de bounces/reclamações em 24h disparar.
├─ maxHardBouncePercent number OPCIONAL
Padrão: 5.0
Limite da taxa de hard bounces em 24 h, em porcentagem.
├─ maxComplaintPercent number OPCIONAL
Padrão: 0.1
Limite máximo da taxa de reclamações ARF em 24 h, em percentual.
├─ allowCriticalWhenTripped boolean OPCIONAL
Padrão: true
Permite e-mails 2FA críticos mesmo com o disjuntor acionado.
├─ enableAdaptiveIspBackoff boolean OPCIONAL
Padrão: false
Cooldown automático quando o MX remoto retorna throttling 421/451.
├─ ispCooldownMinutes integer OPCIONAL
Padrão: 15
Duração do cooldown em minutos.
├─ webhookEnabled boolean OPCIONAL
Padrão: false
Ativa webhooks assinados com HMAC-SHA256.
├─ webhookUrl string OPCIONAL
URL HTTPS de destino para webhooks.
├─ webhookSecret string SOMENTE ESCRITA (SEGREDO)
Segredo HMAC-SHA256 para X-Nextxch-Signature.
{
  "preset": "recommended",
  "enableSuppressionPreCheck": true,
  "autoSuppressHardBounces": true,
  "hardBounceSuppressionDays": 180,
  "enableOneClickUnsubscribe": true,
  "oneClickUnsubscribeCategories": ["marketing", "notification"],
  "enableBounceCircuitBreaker": true,
  "maxHardBouncePercent": 5.0,
  "maxComplaintPercent": 0.1,
  "allowCriticalWhenTripped": true,
  "enableAdaptiveIspBackoff": true,
  "webhookEnabled": true,
  "webhookUrl": "https://erp.firma.de/webhooks/nextxch"
}
# Empfohlenen Reputationsschutz aktivieren:
nextxch-cli update ReputationShield --set preset=recommended

# Webhook-Ziel konfigurieren:
nextxch-cli update ReputationShield \
  --set webhookEnabled=true \
  --set webhookUrl=https://erp.firma.de/webhooks/nextxch \
  --set webhookSecret=whsec_9f8e7d6c5b4a
curl -fsS -X PATCH "https://mail.firma.de/api/admin/cli/objects/ReputationShield/singleton" \
  -H "Authorization: Bearer smk_..." \
  -H "Content-Type: application/json" \
  -d '{"preset":"recommended"}'
await http.PatchAsJsonAsync(
    "/api/admin/cli/objects/ReputationShield/singleton",
    new { preset = "recommended" });
Política singleton

SpamGuard (Singleton)

Chave: singleton RBAC: ServerAdmin+
15 propriedades

Defesa de entrada em várias etapas: verificação SPF/DKIM/DMARC/ARC, Smart Greylisting (/24 IPv4 & /64 IPv6), classificador de ML online (FTRL-Proximal), zonas DNSBL, listas de permissões/bloqueio e verificação ClamAV via TCP.

GET /api/admin/cli/objects/SpamGuard/singleton Obtém os limites do SpamGuard & os contadores de treinamento
PATCH /api/admin/cli/objects/SpamGuard/singleton Atualiza pontuações, DNSBLs, listas de permissões ou o ClamAV no local
{ } Esquema de objetos e propriedades tipadas application/json · camelCase
├─ enableEmailAuthChecks boolean OPCIONAL
Padrão: true
Verifica SPF, DKIM, DMARC e ARC de entrada.
├─ enableGreylisting boolean OPCIONAL
Padrão: true
Smart Greylisting adaptativo para remetentes desconhecidos de primeira vez.
├─ greylistRetryDelaySeconds integer OPCIONAL
Padrão: 240
Atraso mínimo entre tentativas em segundos (padrão: 240s).
├─ junkScoreThreshold number OPCIONAL
Padrão: 4.5
Limite de pontuação para mover para a pasta Spam.
├─ rejectScoreThreshold number OPCIONAL
Padrão: 9.0
Limite de pontuação para rejeição definitiva com SMTP 550.
├─ tagSubjectOnJunk boolean OPCIONAL
Padrão: false
Adiciona um prefixo ao assunto de mensagens de spam.
├─ subjectTagPrefix string OPCIONAL
Padrão: "[SPAM] "
String do prefixo do assunto.
├─ enableStructuralHeuristics boolean OPCIONAL
Padrão: true
Avalia heurísticas estruturais de MIME/HTML.
├─ dnsblZones string[] OPCIONAL
Padrão: ["bl.spamcop.net","ix.dnsbl.manitu.net"]
Zonas DNSBL consultadas.
├─ dnsblHitScore number OPCIONAL
Padrão: 3.5
Pontuação adicionada por ocorrência em DNSBL.
├─ allowedSendersOrDomains string[] OPCIONAL
Padrão: []
Lista de permissões explícita de e-mails ou domínios remetentes.
├─ blockedSendersOrDomains string[] OPCIONAL
Padrão: []
Lista de bloqueio explícita de e-mails ou domínios remetentes.
├─ clamAvEnabled boolean OPCIONAL
Padrão: false
Ativa a verificação ClamAV via TCP INSTREAM do daemon.
├─ clamAvHost string OPCIONAL
Padrão: "127.0.0.1"
Host ou IP do daemon ClamAV.
├─ clamAvPort integer OPCIONAL
Padrão: 3310
Porta TCP do daemon ClamAV.
{
  "enableEmailAuthChecks": true,
  "enableGreylisting": true,
  "greylistRetryDelaySeconds": 240,
  "junkScoreThreshold": 4.5,
  "rejectScoreThreshold": 9.0,
  "enableStructuralHeuristics": true,
  "dnsblZones": ["bl.spamcop.net", "ix.dnsbl.manitu.net"],
  "dnsblHitScore": 3.5,
  "allowedSendersOrDomains": ["datev.de", "partner-spedition.de"],
  "blockedSendersOrDomains": [],
  "clamAvEnabled": false,
  "clamAvHost": "127.0.0.1",
  "clamAvPort": 3310
}
# Partner-Domains auf die Allowlist setzen:
nextxch-cli update SpamGuard \
  --set allowedSendersOrDomains=datev.de,partner-spedition.de

# Schwellenwerte anpassen:
nextxch-cli update SpamGuard --set junkScoreThreshold=4.5 --set rejectScoreThreshold=9.0
curl -fsS -X PATCH "https://mail.firma.de/api/admin/cli/objects/SpamGuard/singleton" \
  -H "Authorization: Bearer smk_..." \
  -H "Content-Type: application/json" \
  -d '{"junkScoreThreshold":4.5,"rejectScoreThreshold":9.0,"allowedSendersOrDomains":["datev.de"]}'
await http.PatchAsJsonAsync(
    "/api/admin/cli/objects/SpamGuard/singleton",
    new { junkScoreThreshold = 4.5, rejectScoreThreshold = 9.0 });
Política singleton

SmtpQueue (Singleton)

Chave: singleton RBAC: ServerAdmin+
19 propriedades

Controla a fila de entrega MX de saída, a concorrência dos workers, os intervalos de novas tentativas, a limitação por ISP, a validação TLS de saída, o smart host global e os limites ESMTP de entrada.

GET /api/admin/cli/objects/SmtpQueue/singleton Obtém todas as configurações de fila, TLS e ESMTP
PATCH /api/admin/cli/objects/SmtpQueue/singleton Atualiza workers da fila, agenda de novas tentativas ou limites ESMTP em 0 ms
{ } Esquema de objetos e propriedades tipadas application/json · camelCase
├─ outboundQueuePaused boolean OPCIONAL
Padrão: false
Pausa a entrega MX de saída enquanto continua aceitando e-mails.
├─ outboundWorkerConcurrency integer OPCIONAL
Padrão: 8
Número de workers paralelos de entrega de saída.
├─ maxDeliveryAttempts integer OPCIONAL
Padrão: 10
Número máximo de tentativas de entrega antes do bounce permanente.
├─ retryScheduleMinutes integer[] OPCIONAL
Padrão: [5,15,60,240,720]
Agenda de backoff de novas tentativas em minutos.
├─ maxConcurrentConnectionsPerMxDomain integer OPCIONAL
Padrão: 4
Máximo de conexões simultâneas por domínio MX de destino.
├─ strictThrottleDomains string[] OPCIONAL
Padrão: ["t-online.de","gmx.de","web.de","yahoo.com"]
Domínios sujeitos a limitação rígida de concorrência.
├─ strictThrottleMaxConcurrency integer OPCIONAL
Padrão: 2
Máximo de conexões simultâneas para strictThrottleDomains.
├─ outboundConnectTimeoutSeconds integer OPCIONAL
Padrão: 30
Timeout de conexão TCP/TLS de saída em segundos.
├─ outboundBindAddress string OPCIONAL
Padrão: "" (Auto)
Endereço IP de origem local opcional para bind.
├─ outboundUseStartTls boolean OPCIONAL
Padrão: true
Usar STARTTLS nas conexões MX de saída.
├─ requireOutboundTls boolean OPCIONAL
Padrão: false
Abortar a entrega se o MX remoto não oferecer TLS.
├─ outboundTlsCertValidation string OPCIONAL
Padrão: Opportunistic
Modo global de validação de certificados X.509 de saída.
Enum:"Opportunistic""IgnoreErrors""Strict"
├─ outboundSmartHost string OPCIONAL
Padrão: ""
Host de relay upstream global opcional.
├─ outboundSmartPort integer OPCIONAL
Padrão: 587
Porta TCP do smart host global.
├─ maxMessageSizeMb long OPCIONAL
Padrão: 50
Limite global de ESMTP SIZE em MiB.
├─ maxRecipientsPerTransaction integer OPCIONAL
Padrão: 100
Máximo de comandos RCPT TO por transação.
├─ maxConnectionsPerIp integer OPCIONAL
Padrão: 20
Número máximo de conexões de entrada simultâneas por IP.
├─ tarpitDelayMs integer OPCIONAL
Padrão: 1500
Atraso de tarpit em ms em erros de autenticação/comando.
├─ requireTlsForAuth boolean OPCIONAL
Padrão: true
Exige criptografia TLS antes de permitir SMTP AUTH.
{
  "outboundQueuePaused": false,
  "outboundWorkerConcurrency": 8,
  "maxDeliveryAttempts": 10,
  "retryScheduleMinutes": [5, 15, 60, 240, 720],
  "maxConcurrentConnectionsPerMxDomain": 4,
  "strictThrottleDomains": ["t-online.de", "gmx.de", "web.de", "yahoo.com"],
  "strictThrottleMaxConcurrency": 2,
  "outboundUseStartTls": true,
  "requireOutboundTls": false,
  "outboundTlsCertValidation": "Opportunistic",
  "maxMessageSizeMb": 50,
  "maxRecipientsPerTransaction": 100,
  "tarpitDelayMs": 1500,
  "requireTlsForAuth": true
}
# Outbound-TLS auf Opportunistic (RFC 7435) setzen & MaxMessageSize auf 75 MiB erhöhen:
nextxch-cli update SmtpQueue \
  --set outboundTlsCertValidation=Opportunistic \
  --set maxMessageSizeMb=75
curl -fsS -X PATCH "https://mail.firma.de/api/admin/cli/objects/SmtpQueue/singleton" \
  -H "Authorization: Bearer smk_..." \
  -H "Content-Type: application/json" \
  -d '{"outboundTlsCertValidation":"Opportunistic","maxMessageSizeMb":75}'
await http.PatchAsJsonAsync(
    "/api/admin/cli/objects/SmtpQueue/singleton",
    new { outboundTlsCertValidation = "Opportunistic", maxMessageSizeMb = 75 });
Política singleton

TransportRules & Server (Singletons)

Chave: singleton RBAC: ServerAdmin+
11 propriedades

Disclaimer jurídico para toda a organização (inserido antes da assinatura DKIM), script Sieve global de entrada, limites de auto-ban do Fail2Ban e ServerHostName canônico.

GET /api/admin/cli/objects/TransportRules/singleton Obtém as configurações de disclaimer, Sieve global e auto-ban
PATCH /api/admin/cli/objects/TransportRules/singleton Atualiza as regras de transporte no local
GET /api/admin/cli/objects/Server/singleton Obtém ServerHostName, mecanismo de armazenamento, tamanho da fila e status da licença
PATCH /api/admin/cli/objects/Server/singleton Atualiza o ServerHostName canônico em 0 ms
{ } Esquema de objetos e propriedades tipadas application/json · camelCase
├─ outboundDisclaimerEnabled boolean OPCIONAL
Padrão: false
Acrescenta um rodapé corporativo obrigatório às mensagens de saída.
├─ outboundDisclaimerExternalOnly boolean OPCIONAL
Padrão: true
Acrescentar rodapé somente ao enviar para domínios externos.
├─ outboundDisclaimerText string OPCIONAL
Padrão: ""
Rodapé legal em texto simples.
├─ outboundDisclaimerHtml string OPCIONAL
Padrão: ""
Rodapé legal em HTML.
├─ inboundSystemSieve string OPCIONAL
Padrão: ""
Script Sieve global (RFC 5228) executado antes dos scripts dos usuários.
├─ autoBanThreshold integer OPCIONAL
Padrão: 8
Logins com falha antes do bloqueio automático do IP.
├─ autoBanDurationMinutes integer OPCIONAL
Padrão: 30
Duração do banimento automático de IP em minutos.
├─ serverHostName string OPCIONAL
Padrão: mail.<domain>
FQDN canônico para EHLO, TLS e Autodiscover (objeto: Server).
├─ storageProvider string SOMENTE LEITURA
Padrão: Sqlite | SqlServer | Postgres
Mecanismo de armazenamento ativo (objeto: Server).
├─ activeQueueCount integer SOMENTE LEITURA
Padrão: 0
Contagem atual da fila de saída (Objeto: Server).
├─ licenseState string SOMENTE LEITURA
Padrão: EnterpriseActive
Status da licença (objeto: Server).
{
  "outboundDisclaimerEnabled": true,
  "outboundDisclaimerExternalOnly": true,
  "outboundDisclaimerText": "-- \nMuster Logistik GmbH · Industriestraße 18 · 70565 Stuttgart · HRB 774819",
  "outboundDisclaimerHtml": "<p style='font-size:11px;color:#64748b'><strong>Muster Logistik GmbH</strong> &middot; 70565 Stuttgart &middot; HRB 774819</p>",
  "inboundSystemSieve": "require [\"fileinto\"];\nif header :contains \"X-Spam-Flag\" \"YES\" { fileinto \"Junk\"; }",
  "autoBanThreshold": 8,
  "autoBanDurationMinutes": 30
}
# Pflicht-Impressum & Auto-Ban aktualisieren:
nextxch-cli update TransportRules \
  --set outboundDisclaimerEnabled=true \
  --set autoBanThreshold=8

# Kanonischen Server-Hostnamen abfragen oder setzen:
nextxch-cli get Server
nextxch-cli update Server --set serverHostName=mail.muster-logistik.de
curl -fsS -X GET "https://mail.firma.de/api/admin/cli/objects/Server/singleton" \
  -H "Authorization: Bearer smk_..."
var status = await http.GetFromJsonAsync<JsonElement>("/api/admin/cli/objects/Server/singleton");
Console.WriteLine($"Host: {status.GetProperty("serverHostName")}, Queue: {status.GetProperty("activeQueueCount")}");