第 14 章 客户端、Groupware & CLI 管理:#pApiAuth

完整的 API & CLI 字段参考:全部 12 种对象类型、REST 端点 & POST /api/v1/send

本参考文档记录了全部 12 个管理对象(/api/admin/cli/objects/{type} & nextxch-cli)以及事务性邮件投递(POST /api/v1/send)的每个 JSON 属性、数据类型、枚举值、默认设置和最低 RBAC 角色。可使用表格上方的即时筛选框搜索任意属性,例如 dkimSigningMode、tlsMode、allowedCidrs 或 warmingEnabled。

运维提示与架构说明

在终端或通过 HTTP 实时内省:每个 nextxch 都在 GET /api/admin/cli/schema 以机器可读的 JSON 提供完整架构(附带 SHA-256 标头 X-Nextxch-Schema-Version)。在终端中,可随时运行 nextxch-cli describe <Type>(例如 nextxch-cli describe Domain 或 nextxch-cli describe SmtpQueue)。

事务性投递

TransactionalSendRequest (POST /api/v1/send)

键:Idempotency-Key RBAC:User+
13 个属性

面向 Web 应用、ERP、CRM 和 2FA 验证码的高吞吐 HTTP JSON 投递端点,支持类别优先级、IP 预热、抑制预检和 24 小时幂等性。

POST /api/v1/send 将事务性邮件加入队列并签名(UTF-8 Multipart/Alternative + 附件)
POST /api/v1/unsubscribe/{token} 公共 RFC 8058 一键退订端点(DKIM 签名令牌)
{ } 对象 Schema 与类型化属性 application/json · camelCase
├─ from string 可选
默认值:Key senderAddress
发件人地址。对于 Role=User 密钥,自动默认为该密钥绑定的 senderAddress。
├─ to string[] 必填
主要收件人电子邮件地址数组(至少需要 1 个)。
├─ cc string[] 可选
默认值:[]
可选的抄送收件人。
├─ bcc string[] 可选
默认值:[]
可选的密件抄送收件人。
├─ replyTo string 可选
可选的 Reply-To 地址。
├─ subject string 必填
电子邮件主题行 (UTF-8)。
├─ textBody string 可选
纯文本正文 (text/plain)。textBody 和 htmlBody 至少需提供一个。
├─ htmlBody string 可选
HTML 正文 (text/html)。与 textBody 一同提供,可实现 10/10 送达率。
├─ category string 可选
默认值:transactional
选择队列优先级、IP 预热绕过以及收件服务商配额分组。
Enum:"critical""transactional""notification""marketing"
├─ overflowMode string 可选
默认值:DeferQueue
达到目标服务商每小时配额时的行为(平滑的队列节奏控制 vs. HTTP 429 + Retry-After)。
Enum:"DeferQueue""Reject429"
├─ idempotencyKey string 可选
默认值:Header Idempotency-Key
确定性去重键(例如发票编号),防止在 24 小时内重复发送。
├─ headers Record<string, string> 可选
默认值:{}
自定义 RFC 5322 X 头字典。
├─ attachments SendAttachmentDto[] 可选
默认值:[]
由 { 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();
集合对象(CRUD)

IntegrationKey (API v1)

键:id RBAC:TenantAdmin+
9 个属性

带权限范围的 /api/v1 集成密钥。密钥代表一个用户执行操作,或作为租户集成,代表 X-Nextxch-Act-As 头中指定的用户。缺少权限范围时 API 返回 403;其他租户的用户返回 404。可选 OAuth 2.0 客户端凭据(令牌有效期 1 小时)。

POST /api/admin/integrations/keys 创建密钥(管理员,仅显示一次)
PUT /api/admin/integrations/keys/{id} 更改范围
DELETE /api/admin/integrations/keys/{id} 吊销密钥(及其 OAuth 令牌)
POST /api/v1/oauth/token OAuth 2.0 client_credentials:使用密钥 ID + 密钥换取访问令牌
GET /api/v1/me 密钥、权限范围和代理用户
GET /api/v1/openapi.json 本安装的 OpenAPI 3.1 文档
{ } 对象 Schema 与类型化属性 application/json · camelCase
├─ label string 必填
标签,例如 CRM 或 ERP。
├─ mode string 必填
默认值:user
user:始终代表 userEmail 执行。tenant:代表 X-Nextxch-Act-As 执行(仅限本租户的用户)。
Enum:"user""tenant"
├─ userEmail string 可选
mode=user 时的用户。
├─ scopes string[] 必填
权限;.write 包含 .read。crypto.read 和 crypto.manage(S/MIME、PGP)为保留权限。
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 可选
租户集成仅限此域的用户。
├─ allowedCidrs string[] 可选
默认值:[]
允许的 IP 网络。
├─ expiresInDays integer 可选
有效期,单位天(留空:无限期)。
├─ senderAddress string 可选
mail.send 的发件人 (POST /api/v1/send)。
├─ apiKey string 只读
smk_<id>_<secret>,仅在创建响应中返回;仅存储其哈希值。
{
  "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");
集合对象(CRUD)

CalendarEvent (API v1)

键:hrefName RBAC:User+
12 个属性

支持系列与例外的日程、参与者、会议室、邀请、答复、忙闲、共享日历和全局日历以及邀请链接。权限范围 calendar.read 和 calendar.write。时间采用 UTC (ISO-8601),时区使用 IANA 名称。

GET /api/v1/calendars 自有、共享、全局和资源日历
GET /api/v1/calendar/events?from&to&calendarId&limit&cursor 时间窗口内的发生次数(已展开重复系列)
POST /api/v1/calendar/events 创建日程(邀请人员和会议室)
GET /api/v1/calendar/events/{hrefName} 带系列和例外的日程
PUT /api/v1/calendar/events/{hrefName} 修改;scope=occurrence|following 用于系列中的部分日程
DELETE /api/v1/calendar/events/{hrefName} 删除,可选择发送取消通知 (notify=true)
POST /api/v1/calendar/events/{hrefName}/respond 回复邀请
POST /api/v1/calendar/events/{hrefName}/invite-link 签名的邀请链接
GET /api/v1/calendar/events/{hrefName}/ics 原始 iCalendar
POST /api/v1/calendar/freebusy 人员和会议室的忙闲
{ } 对象 Schema 与类型化属性 application/json · camelCase
├─ title string 必填
标题。
├─ startUtc datetime 必填
开始时间(UTC)。
├─ endUtc datetime 必填
结束时间(UTC)。
├─ timeZone string 可选
默认值:Europe/Berlin
日程的 IANA 时区(系列、显示)。
├─ allDay boolean 可选
默认值:false
全天。
├─ attendees Attendee[] 可选
默认值:[]
{ email, name, role };会议室和资源按其规则接受或拒绝。
├─ sendInvitations boolean 可选
默认值:false
发送 iMIP 邀请。
├─ recurrence 重复 可选
{ freq, interval, byDay, byMonthDay, count, until }。
├─ showAs string 可选
默认值:busy
显示为。
Enum:"free""tentative""busy""oof""workingElsewhere"
├─ isPrivate boolean 可选
默认值:false
私密(详细信息仅对所有者可见)。
├─ calendarId string 可选
具有写入权限的目标日历 ownerId:slug。
├─ teamsMeeting boolean 可选
创建 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()!;
集合对象(CRUD)

Rooms & Booking (API v1)

键:id RBAC:User+
6 个属性

带可用性信息的会议室和资源(rooms.read),以及类似 Calendly 的预约页面(booking.read、booking.write):预约页面、活动类型、空闲时段、读取和取消预约。会议室通过将其作为参与者的日程进行预订。

GET /api/v1/rooms?startUtc&endUtc&category 会议室和资源,以及该时间窗口内的空闲状态
GET /api/v1/rooms/{email}/availability 某个会议室的忙碌时间
GET /api/v1/booking/profile 带营业时间和日程类型的预约页面
GET /api/v1/booking/event-types 事件类型
POST /api/v1/booking/event-types 创建日程类型
GET /api/v1/booking/event-types/{id}/slots?from&to 空闲开始时间(最多 42 天)
GET /api/v1/booking/bookings?status&from&to 预约
POST /api/v1/booking/bookings/{id}/cancel 取消预约(会通知访客)
{ } 对象 Schema 与类型化属性 application/json · camelCase
├─ slots[].startUtc datetime 只读
空闲开始时间 (UTC)。
├─ slots[].endUtc datetime 只读
结束时间(开始时间加时长)。
├─ slots[].staff object[] 只读
团队日程类型的空闲人员。
├─ status string 只读
预约状态。
Enum:"confirmed""cancelled"
├─ guest object 只读
{ name, email, phone, timeZone }。
├─ free boolean 只读
该时间窗口内会议室空闲。
{
  "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());
集合对象(CRUD)

Contact, Directory & Sharing (API v1)

键:hrefName RBAC:User+
9 个属性

包含全部字段和照片的个人联系人(contacts.read、contacts.write,使用 If-Match 防止冲突)、全局地址列表 (directory.read) 以及共享和委派(sharing.manage,委派 = 带 sendAs 或 sendOnBehalf 的邮箱授权)。

GET /api/v1/contacts?q 搜索联系人
POST /api/v1/contacts 创建联系人
PUT /api/v1/contacts/{hrefName} 修改联系人(null 字段保持不变)
DELETE /api/v1/contacts/{hrefName} 删除联系人
GET /api/v1/directory?q&type 全局地址列表
GET /api/v1/sharing/grants 自有授权
PUT /api/v1/sharing/grants 设置或移除授权
GET /api/v1/sharing/shared-with-me 与我共享
{ } 对象 Schema 与类型化属性 application/json · camelCase
├─ givenName string 可选
名。
├─ familyName string 可选
姓氏。
├─ organization string 可选
公司。
├─ emails TypedValue[] 可选
默认值:[]
{ type: work|home|other, value }。
├─ phones TypedValue[] 可选
默认值:[]
{ type: cell|work|home|fax, value }。
├─ addresses Address[] 可选
默认值:[]
{ type, street, city, region, postalCode, country }。
├─ birthday string 可选
yyyy-MM-dd 或 --MM-dd。
├─ photo string 只写(机密)
data:image/jpeg;base64,...(最大 512 KB),留空则删除。
├─ permissions string[] 可选
授权的权限 (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" }
});
集合对象(CRUD)

Webhook (API v1)

键:id RBAC:User+
4 个属性

事件以签名的 JSON POST 发送:calendar.event.created、calendar.event.updated、calendar.event.deleted、calendar.invitation.replied、booking.created、booking.rescheduled、booking.cancelled。签名 X-Nextxch-Signature: v1=hex(HMAC-SHA256(secret, X-Nextxch-Timestamp + "." + body))。分别在 30 秒、2 分钟、10 分钟、1 小时和 6 小时后重试。

GET /api/v1/webhooks 租户的 Webhook
POST /api/v1/webhooks 注册 webhook(密钥仅在响应中返回)
DELETE /api/v1/webhooks/{id} 删除 webhook
GET /api/v1/webhooks/{id}/deliveries 最近投递
POST /api/v1/webhooks/{id}/test 发送测试事件
{ } 对象 Schema 与类型化属性 application/json · camelCase
├─ url string 必填
HTTPS 目标(内部地址会被阻止)。
├─ events string[] 必填
日程;密钥需要相应的 .read 范围。
Enum:"calendar.event.created""calendar.event.updated""calendar.event.deleted""calendar.invitation.replied""booking.created""booking.rescheduled""booking.cancelled""*"
├─ secret string 只读
whsec_...,仅在创建时返回;加密存储。
├─ id (Ereignis) string 只读
evt_...,每次变更稳定不变,用于去重。
{
  "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();
});
集合对象(CRUD)

Tenant

键:slug RBAC:ServerAdmin+
11 个属性

多租户组织边界,隔离域、主体、存储配额 (GiB) 以及默认 GoBD WORM 合规保留。

GET /api/admin/cli/objects/Tenant 列出所有租户
GET /api/admin/cli/objects/Tenant/{slugOrId} 按 slug 或 UUID 获取租户
POST /api/admin/cli/objects/Tenant 创建新租户
PATCH /api/admin/cli/objects/Tenant/{slugOrId} 就地更新租户配额
{ } 对象 Schema 与类型化属性 application/json · camelCase
├─ id guid 只读
默认值:UUIDv7
内部不可变的 UUIDv7 标识符。
├─ slug string PRIMARY KEY
唯一的 URL 安全租户键(例如 "default"、"acme")。
├─ name string 必填
便于识别的组织显示名称。
├─ isActive boolean 可选
默认值:true
启用或暂停租户。
├─ maxDomains integer 可选
默认值:100
此租户允许的最大域数量。
├─ maxPrincipals integer 可选
默认值:10000
最大账户和通讯组列表数量。
├─ quotaGb integer 可选
默认值:100
租户存储上限(GiB)。
├─ outboundDailyLimit integer 可选
默认值:25000
整个租户每天的最大外发邮件数。
├─ defaultLockMode string 可选
默认值:Normal
新建域的默认 GoBD WORM 锁定模式。
Enum:"Normal""Governance""Compliance""LegalHold"
├─ defaultRetentionDays integer 可选
默认值:0
默认强制保留期,单位天(3650 = GoBD 规定的 10 年)。
├─ createdAtUtc datetime 只读
创建时间戳 (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);
集合对象(CRUD)

Domain

键:name RBAC:TenantAdmin+
19 个属性

托管的邮件域,自动并行生成双 DKIM 密钥(RSA-2048 + Ed25519),并支持 GoBD WORM 保留策略、加号寻址和速率限制。

GET /api/admin/cli/objects/Domain 列出所有域
GET /api/admin/cli/objects/Domain/{name} 获取域配置 & DKIM 选择器
POST /api/admin/cli/objects/Domain 创建域 & 生成 RSA-2048 + Ed25519 DKIM 密钥
PATCH /api/admin/cli/objects/Domain/{name} 在 0 ms 内更新 DKIM 模式、配额或保留设置
GET /api/admin/cli/dns/{name}?live=true 验证实时 DNS 记录或导出 RFC 1035 BIND 区域
{ } 对象 Schema 与类型化属性 application/json · camelCase
├─ id guid 只读
默认值:UUIDv7
内部域 UUIDv7。
├─ name string PRIMARY KEY
DNS 域名(例如 "muster-logistik.de")。
├─ tenant string 可选
默认值:default
所属租户的 slug 或 GUID。
├─ isActive boolean 可选
默认值:true
启用或暂停域。
├─ postmasterAddress string 可选
默认值:postmaster@<name>
RFC 5321 postmaster 联系地址。
├─ dkimSigningMode string 可选
默认值:Dual
当前 DKIM 签名模式(Dual 同时使用 RSA-2048 和 Ed25519 签名)。
Enum:"Rsa2048""Ed25519""Dual"
├─ dkimRsaSelector string 可选
默认值:s2026
RSA-2048 DNS 选择器。
├─ dkimRsaDnsName string 只读
默认值:s2026._domainkey.<name>
计算得出的 RSA-2048 _domainkey FQDN。
├─ dkimEd25519Selector string 可选
默认值:ed2026
Ed25519 DNS 选择器。
├─ dkimEd25519DnsName string 只读
默认值:ed2026._domainkey.<name>
计算得出的 Ed25519 _domainkey FQDN。
├─ retentionLockMode string 可选
默认值:Normal
此域的 GoBD WORM 归档锁定模式。
Enum:"Normal""Governance""Compliance""LegalHold"
├─ retentionDays integer 可选
默认值:0
强制保留期,单位为天(3650 = 10 年 GoBD)。
├─ quotaGb integer 可选
默认值:50
域存储上限(GiB)。
├─ maxMessageSizeMb integer 可选
默认值:50
最大邮件大小,单位 MiB。
├─ maxAccounts integer 可选
默认值:1000
此域中的最大邮箱数。
├─ outboundDailyLimit integer 可选
默认值:5000
此域的每日出站发送上限。
├─ outboundHourlyLimit integer 可选
默认值:1000
此域每小时的外发邮件限额。
├─ usePlusAddressing boolean 可选
默认值:true
启用 RFC 5233 加号寻址(user+tag@domain)。
├─ createdAtUtc datetime 只读
创建时间戳 (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();
集合对象(CRUD)

Account (Account/User & Account/List)

键:email RBAC:TenantAdmin+
18 个属性

表示用户邮箱(@type="User",支持 IMAP/JMAP/CalDAV/CardDAV/ActiveSync)或通讯组列表(@type="List",带 members[])。

GET /api/admin/cli/objects/Account?filter=role=TenantAdmin 列出/筛选账户和通讯组列表
POST /api/admin/cli/objects/Account/User 创建带 RFC 6154 文件夹的新用户邮箱
POST /api/admin/cli/objects/Account/List 创建新的通讯组列表
PATCH /api/admin/cli/objects/Account/{email} 更新配额、转发、自动回复或密码
DELETE /api/admin/cli/objects/Account/{email} 软删除账户
{ } 对象 Schema 与类型化属性 application/json · camelCase
├─ id guid 只读
默认值:UUIDv7
内部主体 UUIDv7。
├─ @type string 可选
默认值:User
账户类型:User 用户邮箱或 List 通讯组。
Enum:"User""List"
├─ email string PRIMARY KEY
邮箱或列表的主电子邮件地址。
├─ displayName string 可选
默认值:Lokalteil
在 Webmail、全局地址列表和 From 标头中显示的名称。
├─ password string 只写(机密)
创建/更新时的明文密码(立即使用 Argon2id 哈希)。
├─ role string 可选
默认值:User
管理 RBAC 角色。
Enum:"User""ComplianceAuditor""TenantAdmin""ServerAdmin"
├─ isActive boolean 可选
默认值:true
启用或暂停账户。
├─ quotaMb integer 可选
默认值:5120
邮箱存储配额,单位 MiB(5120 = 5 GiB)。
├─ usedBytes long 只读
默认值:0
当前邮箱存储用量,单位字节。
├─ outboundDailyLimit integer 可选
默认值:500
此账户每天的外发邮件限额。
├─ forwardAddress string 可选
可选的 SRS 安全转发目标电子邮件地址。
├─ forwardKeepOriginal boolean 可选
默认值:true
启用转发时在 INBOX 中保留本地副本。
├─ vacationEnabled boolean 可选
默认值:false
启用自动外出回复。
├─ vacationSubject string 可选
外出自动回复主题。
├─ vacationBody string 只写(机密)
外出自动回复正文。
├─ twoFactorEnabled boolean 只读
默认值:false
指示 TOTP 2FA 是否已启用。
├─ members string[] 可选
默认值:[]
成员电子邮件地址(适用于 @type="List")。
├─ createdAtUtc datetime 只读
创建时间戳 (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
});
集合对象(CRUD)

Alias

键:address RBAC:TenantAdmin+
7 个属性

次要电子邮件别名或一次性隐私掩码别名,路由到主 Account 邮箱或通讯组列表。

GET /api/admin/cli/objects/Alias 列出所有别名和隐藏式邮箱地址
POST /api/admin/cli/objects/Alias 创建一个路由到目标邮箱的新别名
PATCH /api/admin/cli/objects/Alias/{address} 启用/暂停别名或更新其目标
DELETE /api/admin/cli/objects/Alias/{address} 删除别名
{ } 对象 Schema 与类型化属性 application/json · camelCase
├─ address string PRIMARY KEY
别名电子邮件地址。
├─ target string 必填
目标主账户电子邮件地址。
├─ principalId guid 只读
解析后的目标主体 UUID。
├─ description string 可选
默认值:""
用途说明或外部服务标签(也会显示在 Webmail 撰写界面中)。
├─ isMasked boolean 可选
默认值:false
将该别名标记为隐私遮罩别名。
├─ isEnabled boolean 可选
默认值:true
为 false 时,发往此别名的邮件将被拒绝,但不释放该地址。
├─ createdAtUtc datetime 只读
创建时间戳 (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
});
集合对象(CRUD)

ApiKey

键:id RBAC:TenantAdmin+
11 个属性

不可变、受 RBAC 和 CIDR 限制的范围化 API 密钥 (smk_<id>_<secret>),用于 /api/v1/send、SCIM 2.0 或 nextxch-cli。

GET /api/admin/cli/objects/ApiKey 列出有效的 API 密钥(不含密钥机密)
POST /api/admin/cli/objects/ApiKey 生成新的 API 密钥,并仅返回一次 apiKey (smk_...)
DELETE /api/admin/cli/objects/ApiKey/{id} 立即撤销 API 密钥
{ } 对象 Schema 与类型化属性 application/json · camelCase
├─ id guid 只读
默认值:UUIDv7
唯一密钥 UUID(用于通过 DELETE 吊销)。
├─ apiKey string 仅创建
默认值:smk_<id>_<secret>
完整的 Bearer 令牌仅在创建时返回一次。
├─ label string 必填
便于识别的标签(例如 "Ansible GitOps" 或 "Shopware 6")。
├─ role string 可选
默认值:TenantAdmin
权限范围(User 严格限于 POST /api/v1/send)。
Enum:"User""ComplianceAuditor""TenantAdmin""ServerAdmin"
├─ senderAddress string 可选
授权的发件人地址(role="User" 时必填)。
├─ defaultCategory string 可选
默认值:transactional
此密钥的默认发送类别。
Enum:"critical""transactional""notification""marketing"
├─ allowedCidrs string[] 可选
默认值:[] (Alle IPs)
允许的源 IPv4/IPv6 CIDR 网络。
├─ expiresInDays integer 只写(机密)
默认值:null (Kein Ablauf)
可选的自动过期时间(自创建起的天数)。
├─ expiresAtUtc datetime 只读
计算得出的 UTC 过期时间戳。
├─ outboundDailyLimit integer 可选
默认值:10000
此密钥的每日出站发送上限。
├─ isActive boolean 只读
默认值:true
启用状态。
{
  "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()!;
集合对象(CRUD)

Route

键:domain RBAC:ServerAdmin+
10 个属性

按域的外发 SMTP 路由或 TLS 证书例外(例如对证书不匹配的合作伙伴 MX 主机使用 StartTlsIgnoreCert,或智能主机连接器)。

GET /api/admin/cli/objects/Route 列出所有自定义出站路由
POST /api/admin/cli/objects/Route 创建自定义域路由或 TLS 覆盖
PATCH /api/admin/cli/objects/Route/{domain} 更新目标主机、端口或 TLS 模式
DELETE /api/admin/cli/objects/Route/{domain} 删除自定义路由
{ } 对象 Schema 与类型化属性 application/json · camelCase
├─ domain string PRIMARY KEY
目标收件人域(例如 "neff.me" 或 "*.partner-holding.eu")。
├─ targetHost string 可选
默认值:"" (Auto DNS-MX)
中继主机名或 IP。留空则通过 DNS 自动解析目标 MX。
├─ targetPort integer 可选
默认值:25
目标 TCP 端口(25、587 或 465)。
├─ tlsMode string 可选
默认值:StartTlsOptional
此域的出站 TLS 与 X.509 验证模式。
Enum:"StartTlsOptional""StartTlsRequired""StartTlsIgnoreCert""ImplicitTls""ImplicitTlsIgnoreCert""None"
├─ username string 可选
可选的 SMTP AUTH 用户名。
├─ password string 只写(机密)
可选的 SMTP AUTH 密码。
├─ hasPassword boolean 只读
默认值:false
指示是否已存储密码。
├─ clearPassword boolean 只写(机密)
默认值:false
设为 true 可清除已存储的密码。
├─ description string 可选
管理员审计备注。
├─ enabled boolean 可选
默认值:true
启用或暂停路由。
{
  "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
});
单例策略

TransactionalSend (Singleton)

键:singleton RBAC:TenantAdmin+
11 个属性

管控渐进式 28 天 IP 预热、邮件类别以及按收件服务商划分的每小时/每日配额(Google、Microsoft、Yahoo/AOL、德国 ISP、iCloud、*)。

GET /api/admin/cli/objects/TransactionalSend/singleton 获取当前的 IP 预热与服务商配额策略
PATCH /api/admin/cli/objects/TransactionalSend/singleton 更新预热天数、预设或服务商配额
{ } 对象 Schema 与类型化属性 application/json · camelCase
├─ enabled boolean 可选
默认值:true
启用类别与服务商配额管控。
├─ warmingEnabled boolean 可选
默认值:false
启用渐进式每日 IP 预热爬坡。
├─ startAtWarmingDay integer 只写(机密)
默认值:1
将预热计划跳转或重置到第 N 天(1..365)。
├─ currentWarmingDay integer 只读
预热计划中的当前活动天数。
├─ currentWarmingPercent integer 只读
目标服务商配额的当前生效百分比。
├─ warmingDailyRampPercents integer[] 可选
默认值:[5,7,10,...,100]
预热爬坡的每日百分比数组。
├─ maxDeferHours integer 可选
默认值:48
DeferQueue 节奏控制的最大前瞻时间窗口(小时)。
├─ defaultCategory string 可选
默认值:transactional
API 调用中省略时使用的回退类别。
Enum:"critical""transactional""notification""marketing"
├─ preset string 只写(机密)
一步式预设选择器。
Enum:"warming_28d""warming_14d""production_100"
├─ categories CategoryPolicy[] 可选
默认值:4 Kategorien
类别策略对象数组。
├─ providers ProviderQuota[] 可选
默认值:6 Provider-Gruppen
收件服务商配额定义数组。
{
  "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 });
单例策略

ReputationShield (Singleton)

键:singleton RBAC:TenantAdmin+
20 个属性

可选的外发信誉保护:自动退信/投诉抑制列表、RFC 8058 一键退订、退信熔断器、自适应 421 ISP 退避,以及 HMAC-SHA256 webhook。

GET /api/admin/cli/objects/ReputationShield/singleton 获取当前 Reputation Shield 配置
PATCH /api/admin/cli/objects/ReputationShield/singleton 更新防护标志或应用预设
{ } 对象 Schema 与类型化属性 application/json · camelCase
├─ preset string 只写(机密)
一步应用完整的防护配置文件。
Enum:"off""recommended""strict_bulk"
├─ enableSuppressionPreCheck boolean 可选
默认值:false
发送前过滤已抑制的地址。
├─ enforceSuppressionOnSmtpRelay boolean 可选
默认值:false
同时在 SMTP 提交时强制执行抑制列表。
├─ allSuppressedBehavior string 可选
默认值:reject_422
所有收件人均被抑制时的响应模式。
Enum:"reject_422""accept_noop"
├─ autoSuppressHardBounces boolean 可选
默认值:false
自动抑制 5xx 永久性硬退信。
├─ hardBounceSuppressionDays integer 可选
默认值:180
硬退信抑制记录的保留天数。
├─ autoSuppressConsecutiveSoftBounces boolean 可选
默认值:false
将重复的 4xx 软退信升级加入抑制列表。
├─ softBounceEscalationThreshold integer 可选
默认值:5
抑制前允许的连续软退信次数。
├─ autoSuppressFblComplaints boolean 可选
默认值:false
自动解析入站 RFC 5965 ARF 滥用报告。
├─ enableOneClickUnsubscribe boolean 可选
默认值:false
注入经 DKIM 签名的 RFC 8058 List-Unsubscribe 头。
├─ oneClickUnsubscribeCategories string[] 可选
默认值:["marketing","notification"]
接收 RFC 8058 退订邮件头的类别。
├─ enableBounceCircuitBreaker boolean 可选
默认值:false
当 24 小时退信/投诉率激增时,暂停非关键发送。
├─ maxHardBouncePercent number 可选
默认值:5.0
24 小时硬退信率上限(百分比)。
├─ maxComplaintPercent number 可选
默认值:0.1
24 小时 ARF 投诉率上限(百分比)。
├─ allowCriticalWhenTripped boolean 可选
默认值:true
即使熔断器已触发,也允许发送关键的 2FA 邮件。
├─ enableAdaptiveIspBackoff boolean 可选
默认值:false
当远程 MX 返回 421/451 限流时自动冷却。
├─ ispCooldownMinutes integer 可选
默认值:15
冷却时长(分钟)。
├─ webhookEnabled boolean 可选
默认值:false
启用 HMAC-SHA256 签名的 webhook。
├─ webhookUrl string 可选
Webhook 的目标 HTTPS URL。
├─ webhookSecret string 只写(机密)
用于 X-Nextxch-Signature 的 HMAC-SHA256 密钥。
{
  "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" });
单例策略

SpamGuard (Singleton)

键:singleton RBAC:ServerAdmin+
15 个属性

多级入站防御:SPF/DKIM/DMARC/ARC 验证、智能灰名单(/24 IPv4 & /64 IPv6)、在线机器学习分类器(FTRL-Proximal)、DNSBL 区域、允许/阻止列表,以及 ClamAV TCP 扫描。

GET /api/admin/cli/objects/SpamGuard/singleton 获取 SpamGuard 阈值 & 训练计数器
PATCH /api/admin/cli/objects/SpamGuard/singleton 就地更新评分、DNSBL、允许列表或 ClamAV
{ } 对象 Schema 与类型化属性 application/json · camelCase
├─ enableEmailAuthChecks boolean 可选
默认值:true
验证入站 SPF、DKIM、DMARC 和 ARC。
├─ enableGreylisting boolean 可选
默认值:true
针对未知首次发件人的自适应智能灰名单。
├─ greylistRetryDelaySeconds integer 可选
默认值:240
最小重试延迟,单位秒(默认值:240 秒)。
├─ junkScoreThreshold number 可选
默认值:4.5
归入垃圾邮件文件夹的评分阈值。
├─ rejectScoreThreshold number 可选
默认值:9.0
触发 SMTP 550 硬拒绝的分数阈值。
├─ tagSubjectOnJunk boolean 可选
默认值:false
为垃圾邮件添加主题前缀。
├─ subjectTagPrefix string 可选
默认值:"[SPAM] "
主题前缀字符串。
├─ enableStructuralHeuristics boolean 可选
默认值:true
评估 MIME/HTML 结构启发式规则。
├─ dnsblZones string[] 可选
默认值:["bl.spamcop.net","ix.dnsbl.manitu.net"]
查询的 DNSBL 区域。
├─ dnsblHitScore number 可选
默认值:3.5
每次命中 DNSBL 增加的分数。
├─ allowedSendersOrDomains string[] 可选
默认值:[]
明确的发件人电子邮件或域允许列表。
├─ blockedSendersOrDomains string[] 可选
默认值:[]
明确的发件人电子邮件或域阻止列表。
├─ clamAvEnabled boolean 可选
默认值:false
启用 ClamAV 守护进程的 TCP INSTREAM 扫描。
├─ clamAvHost string 可选
默认值:"127.0.0.1"
ClamAV 守护进程主机或 IP。
├─ clamAvPort integer 可选
默认值:3310
ClamAV 守护进程 TCP 端口。
{
  "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 });
单例策略

SmtpQueue (Singleton)

键:singleton RBAC:ServerAdmin+
19 个属性

控制出站 MX 投递队列、工作线程并发数、重试间隔、ISP 限流、出站 TLS 验证、全局智能主机以及入站 ESMTP 限制。

GET /api/admin/cli/objects/SmtpQueue/singleton 获取所有队列、TLS 和 ESMTP 设置
PATCH /api/admin/cli/objects/SmtpQueue/singleton 在 0 ms 内更新队列工作线程、重试计划或 ESMTP 限制
{ } 对象 Schema 与类型化属性 application/json · camelCase
├─ outboundQueuePaused boolean 可选
默认值:false
暂停出站 MX 投递,同时继续接收邮件。
├─ outboundWorkerConcurrency integer 可选
默认值:8
并行出站投递工作线程数。
├─ maxDeliveryAttempts integer 可选
默认值:10
永久退信前的最大投递尝试次数。
├─ retryScheduleMinutes integer[] 可选
默认值:[5,15,60,240,720]
重试退避计划(分钟)。
├─ maxConcurrentConnectionsPerMxDomain integer 可选
默认值:4
每个目标 MX 域的最大并发连接数。
├─ strictThrottleDomains string[] 可选
默认值:["t-online.de","gmx.de","web.de","yahoo.com"]
受严格并发限流约束的域。
├─ strictThrottleMaxConcurrency integer 可选
默认值:2
strictThrottleDomains 的最大并发连接数。
├─ outboundConnectTimeoutSeconds integer 可选
默认值:30
出站 TCP/TLS 连接超时(秒)。
├─ outboundBindAddress string 可选
默认值:"" (Auto)
可选的本地源 IP 绑定地址。
├─ outboundUseStartTls boolean 可选
默认值:true
在出站 MX 连接上使用 STARTTLS。
├─ requireOutboundTls boolean 可选
默认值:false
如果远程 MX 不提供 TLS,则中止投递。
├─ outboundTlsCertValidation string 可选
默认值:Opportunistic
全局出站 X.509 证书验证模式。
Enum:"Opportunistic""IgnoreErrors""Strict"
├─ outboundSmartHost string 可选
默认值:""
可选的全局上游中继主机。
├─ outboundSmartPort integer 可选
默认值:587
全局智能主机 TCP 端口。
├─ maxMessageSizeMb long 可选
默认值:50
全局 ESMTP SIZE 限制,单位 MiB。
├─ maxRecipientsPerTransaction integer 可选
默认值:100
每个事务允许的最大 RCPT TO 命令数。
├─ maxConnectionsPerIp integer 可选
默认值:20
每个 IP 的最大并发入站连接数。
├─ tarpitDelayMs integer 可选
默认值:1500
认证/命令错误时的 Tarpit 延迟(毫秒)。
├─ requireTlsForAuth boolean 可选
默认值:true
要求先进行 TLS 加密,才允许 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 });
单例策略

TransportRules & Server (Singletons)

键:singleton RBAC:ServerAdmin+
11 个属性

组织范围的法律免责声明(在 DKIM 签名之前插入)、全局入站 Sieve 脚本、Fail2Ban 自动封禁阈值以及规范的 ServerHostName。

GET /api/admin/cli/objects/TransportRules/singleton 获取免责声明、全局 Sieve 和自动封禁设置
PATCH /api/admin/cli/objects/TransportRules/singleton 原地更新传输规则
GET /api/admin/cli/objects/Server/singleton 获取 ServerHostName、存储引擎、队列深度和许可证状态
PATCH /api/admin/cli/objects/Server/singleton 0 ms 内更新规范的 ServerHostName
{ } 对象 Schema 与类型化属性 application/json · camelCase
├─ outboundDisclaimerEnabled boolean 可选
默认值:false
在出站邮件末尾附加强制性的公司页脚。
├─ outboundDisclaimerExternalOnly boolean 可选
默认值:true
仅在发送到外部域时追加页脚。
├─ outboundDisclaimerText string 可选
默认值:""
纯文本法律页脚。
├─ outboundDisclaimerHtml string 可选
默认值:""
HTML 法律页脚。
├─ inboundSystemSieve string 可选
默认值:""
在用户脚本之前执行的全局 RFC 5228 Sieve 脚本。
├─ autoBanThreshold integer 可选
默认值:8
触发自动 IP 封禁前允许的登录失败次数。
├─ autoBanDurationMinutes integer 可选
默认值:30
自动封禁 IP 的时长(分钟)。
├─ serverHostName string 可选
默认值:mail.<domain>
规范的 EHLO、TLS 和 Autodiscover FQDN(对象:Server)。
├─ storageProvider string 只读
默认值:Sqlite | SqlServer | Postgres
当前存储引擎(对象:Server)。
├─ activeQueueCount integer 只读
默认值:0
当前出站队列数量(对象:Server)。
├─ licenseState string 只读
默认值:EnterpriseActive
许可证状态(对象: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")}");