SharpMailserver SHARPMAILSERVER
Chapter 12 Clients, Groupware & CLI Admin: #pApiAuth

Complete API & CLI Field Reference: All 12 Object Types, REST Endpoints & POST /api/v1/send

This reference documents every JSON property, data type, enum value, default setting, and minimum RBAC role across all 12 management objects (/api/admin/cli/objects/{type} & sharpmail-cli) as well as transactional email delivery (POST /api/v1/send). Use the instant filter box above the table to search any property such as dkimSigningMode, tlsMode, allowedCidrs, or warmingEnabled.

Operational Tip & Architecture Note

Live introspection in your terminal or via HTTP: every SharpMailserver exposes this complete schema in machine-readable JSON at GET /api/admin/cli/schema (with SHA-256 header X-SharpMail-Schema-Version). In your terminal, run sharpmail-cli describe <Type> (e.g. sharpmail-cli describe Domain or sharpmail-cli describe SmtpQueue) at any time.

Transactional Delivery

TransactionalSendRequest (POST /api/v1/send)

Key: Idempotency-Key RBAC: User+
13 Properties

High-throughput HTTP JSON delivery endpoint for web apps, ERPs, CRMs, and 2FA codes with category prioritization, IP warming, suppression pre-check, and 24h idempotency.

POST /api/v1/send Enqueues and signs transactional email (UTF-8 Multipart/Alternative + attachments)
POST /api/v1/unsubscribe/{token} Public RFC 8058 One-Click-Unsubscribe endpoint (DKIM-signed token)
{ } Object Schema & Typed Properties application/json · camelCase
├─ from string OPTIONAL
Default: Key senderAddress
Sender address. Automatically defaults to the key's bound senderAddress for Role=User keys.
├─ to string[] REQUIRED
Array of primary recipient email addresses (at least 1 required).
├─ cc string[] OPTIONAL
Default: []
Optional carbon-copy recipients.
├─ bcc string[] OPTIONAL
Default: []
Optional blind carbon-copy recipients.
├─ replyTo string OPTIONAL
Optional Reply-To address.
├─ subject string REQUIRED
Email subject line (UTF-8).
├─ textBody string OPTIONAL
Plain-text body (text/plain). At least one of textBody or htmlBody is required.
├─ htmlBody string OPTIONAL
HTML body (text/html). Supply alongside textBody for 10/10 deliverability.
├─ category string OPTIONAL
Default: transactional
Selects queue priority, IP warming bypass, and recipient-provider quota bucket.
Enum:"critical""transactional""notification""marketing"
├─ overflowMode string OPTIONAL
Default: DeferQueue
Behavior when destination provider hourly quota is reached (smooth queue pacing vs. HTTP 429 + Retry-After).
Enum:"DeferQueue""Reject429"
├─ idempotencyKey string OPTIONAL
Default: Header Idempotency-Key
Deterministic deduplication key (e.g. invoice ID) preventing duplicate sends within 24 hours.
├─ headers Record<string, string> OPTIONAL
Default: {}
Custom RFC 5322 X-headers dictionary.
├─ attachments SendAttachmentDto[] OPTIONAL
Default: []
Array of { 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:
sharpmail-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.sharpmail.local | bounce@sink.sharpmail.local | defer@sink.sharpmail.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();
Collection Object (CRUD)

Tenant

Key: slug RBAC: ServerAdmin+
11 Properties

Multi-tenant organization boundary isolating domains, principals, storage quotas (GiB), and default GoBD WORM compliance retention.

GET /api/admin/cli/objects/Tenant Lists all tenants
GET /api/admin/cli/objects/Tenant/{slugOrId} Gets tenant by slug or UUID
POST /api/admin/cli/objects/Tenant Creates a new tenant
PATCH /api/admin/cli/objects/Tenant/{slugOrId} Updates tenant quotas in place
{ } Object Schema & Typed Properties application/json · camelCase
├─ id guid READ-ONLY
Default: UUIDv7
Internal immutable UUIDv7 identifier.
├─ slug string PRIMARY KEY
Unique URL-safe tenant key (e.g. "default", "acme").
├─ name string REQUIRED
Human-readable organization display name.
├─ isActive boolean OPTIONAL
Default: true
Enable or suspend tenant.
├─ maxDomains integer OPTIONAL
Default: 100
Maximum domains allowed in this tenant.
├─ maxPrincipals integer OPTIONAL
Default: 10000
Maximum accounts and distribution lists.
├─ quotaGb integer OPTIONAL
Default: 100
Tenant storage ceiling in GiB.
├─ outboundDailyLimit integer OPTIONAL
Default: 25000
Maximum outbound emails per day across the tenant.
├─ defaultLockMode string OPTIONAL
Default: Normal
Default GoBD WORM lock mode for newly created domains.
Enum:"Normal""Governance""Compliance""LegalHold"
├─ defaultRetentionDays integer OPTIONAL
Default: 0
Default mandatory retention period in days (3650 = 10y GoBD).
├─ createdAtUtc datetime READ-ONLY
Creation timestamp in UTC.
{
  "slug": "acme",
  "name": "ACME Logistik GmbH",
  "isActive": true,
  "maxDomains": 50,
  "maxPrincipals": 2500,
  "quotaGb": 250,
  "outboundDailyLimit": 25000,
  "defaultLockMode": "Compliance",
  "defaultRetentionDays": 3650
}
# Mandant anlegen:
sharpmail-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:
sharpmail-cli get Tenant acme
sharpmail-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);
Collection Object (CRUD)

Domain

Key: name RBAC: TenantAdmin+
19 Properties

Hosted mail domain with automatic parallel Dual-DKIM key generation (RSA-2048 + Ed25519), GoBD WORM retention policy, plus-addressing, and rate limits.

GET /api/admin/cli/objects/Domain Lists all domains
GET /api/admin/cli/objects/Domain/{name} Gets domain configuration & DKIM selectors
POST /api/admin/cli/objects/Domain Creates domain & generates RSA-2048 + Ed25519 DKIM keys
PATCH /api/admin/cli/objects/Domain/{name} Updates DKIM mode, quotas, or retention in 0 ms
GET /api/admin/cli/dns/{name}?live=true Verifies live DNS records or exports RFC 1035 BIND zone
{ } Object Schema & Typed Properties application/json · camelCase
├─ id guid READ-ONLY
Default: UUIDv7
Internal domain UUIDv7.
├─ name string PRIMARY KEY
DNS domain name (e.g. "muster-logistik.de").
├─ tenant string OPTIONAL
Default: default
Owning tenant slug or GUID.
├─ isActive boolean OPTIONAL
Default: true
Enable or pause domain.
├─ postmasterAddress string OPTIONAL
Default: postmaster@<name>
RFC 5321 postmaster contact address.
├─ dkimSigningMode string OPTIONAL
Default: Dual
Active DKIM signing mode (Dual signs with both RSA-2048 and Ed25519).
Enum:"Rsa2048""Ed25519""Dual"
├─ dkimRsaSelector string OPTIONAL
Default: s2026
RSA-2048 DNS selector.
├─ dkimRsaDnsName string READ-ONLY
Default: s2026._domainkey.<name>
Computed RSA-2048 _domainkey FQDN.
├─ dkimEd25519Selector string OPTIONAL
Default: ed2026
Ed25519 DNS selector.
├─ dkimEd25519DnsName string READ-ONLY
Default: ed2026._domainkey.<name>
Computed Ed25519 _domainkey FQDN.
├─ retentionLockMode string OPTIONAL
Default: Normal
GoBD WORM archive lock mode for this domain.
Enum:"Normal""Governance""Compliance""LegalHold"
├─ retentionDays integer OPTIONAL
Default: 0
Mandatory retention duration in days (3650 = 10y GoBD).
├─ quotaGb integer OPTIONAL
Default: 50
Domain storage ceiling in GiB.
├─ maxMessageSizeMb integer OPTIONAL
Default: 50
Maximum message size in MiB.
├─ maxAccounts integer OPTIONAL
Default: 1000
Maximum mailboxes in this domain.
├─ outboundDailyLimit integer OPTIONAL
Default: 5000
Daily outbound send limit for this domain.
├─ outboundHourlyLimit integer OPTIONAL
Default: 1000
Hourly outbound send limit for this domain.
├─ usePlusAddressing boolean OPTIONAL
Default: true
Enables RFC 5233 plus-addressing (user+tag@domain).
├─ createdAtUtc datetime READ-ONLY
Creation timestamp in 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:
sharpmail-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:
sharpmail-cli dns muster-logistik.de --bind > muster-logistik.de.zone
sharpmail-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();
Collection Object (CRUD)

Account (Account/User & Account/List)

Key: email RBAC: TenantAdmin+
18 Properties

Represents a user mailbox (@type="User", with IMAP/JMAP/CalDAV/CardDAV/ActiveSync) or a distribution list (@type="List" with members[]).

GET /api/admin/cli/objects/Account?filter=role=TenantAdmin Lists/filters accounts and distribution lists
POST /api/admin/cli/objects/Account/User Creates a new user mailbox with RFC 6154 folders
POST /api/admin/cli/objects/Account/List Creates a new distribution list
PATCH /api/admin/cli/objects/Account/{email} Updates quota, forwarding, vacation, or password
DELETE /api/admin/cli/objects/Account/{email} Soft-deletes an account
{ } Object Schema & Typed Properties application/json · camelCase
├─ id guid READ-ONLY
Default: UUIDv7
Internal principal UUIDv7.
├─ @type string OPTIONAL
Default: User
Account variant: User mailbox or List distribution group.
Enum:"User""List"
├─ email string PRIMARY KEY
Primary email address of the mailbox or list.
├─ displayName string OPTIONAL
Default: Lokalteil
Display name shown in Webmail, GAL, and From headers.
├─ password string WRITE-ONLY (SECRET)
Plaintext password on create/update (immediately hashed with Argon2id).
├─ role string OPTIONAL
Default: User
Administrative RBAC role.
Enum:"User""ComplianceAuditor""TenantAdmin""ServerAdmin"
├─ isActive boolean OPTIONAL
Default: true
Enable or suspend account.
├─ quotaMb integer OPTIONAL
Default: 5120
Mailbox storage quota in MiB (5120 = 5 GiB).
├─ usedBytes long READ-ONLY
Default: 0
Current mailbox storage usage in bytes.
├─ outboundDailyLimit integer OPTIONAL
Default: 500
Daily outbound message limit for this account.
├─ forwardAddress string OPTIONAL
Optional SRS-safe forwarding destination email.
├─ forwardKeepOriginal boolean OPTIONAL
Default: true
Keep a local copy in INBOX when forwarding is active.
├─ vacationEnabled boolean OPTIONAL
Default: false
Enable automatic out-of-office responder.
├─ vacationSubject string OPTIONAL
Out-of-office auto-reply subject.
├─ vacationBody string WRITE-ONLY (SECRET)
Out-of-office auto-reply body text.
├─ twoFactorEnabled boolean READ-ONLY
Default: false
Indicates whether TOTP 2FA is active.
├─ members string[] OPTIONAL
Default: []
Member email addresses (for @type="List").
├─ createdAtUtc datetime READ-ONLY
Creation timestamp in 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:
sharpmail-cli create Account/User \
  --set email=anna.weber@muster-logistik.de \
  --set displayName="Anna Weber" \
  --set password="SicheresStartPasswort!2026" \
  --set quotaMb=15360

# Verteilerliste anlegen:
sharpmail-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
});
Collection Object (CRUD)

Alias

Key: address RBAC: TenantAdmin+
7 Properties

Secondary email alias or disposable masked privacy alias routed to a primary Account mailbox or distribution list.

GET /api/admin/cli/objects/Alias Lists all aliases and masked emails
POST /api/admin/cli/objects/Alias Creates a new alias routed to a target mailbox
PATCH /api/admin/cli/objects/Alias/{address} Enables/pauses an alias or updates its target
DELETE /api/admin/cli/objects/Alias/{address} Deletes the alias
{ } Object Schema & Typed Properties application/json · camelCase
├─ address string PRIMARY KEY
The alias email address.
├─ target string REQUIRED
Target primary Account email address.
├─ principalId guid READ-ONLY
Resolved target principal UUID.
├─ description string OPTIONAL
Default: ""
Purpose note or external service label (also shown in Webmail composer).
├─ isMasked boolean OPTIONAL
Default: false
Marks the alias as a masked privacy alias.
├─ isEnabled boolean OPTIONAL
Default: true
When false, mail to this alias is rejected without releasing the address.
├─ createdAtUtc datetime READ-ONLY
Creation timestamp in 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:
sharpmail-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:
sharpmail-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
});
Collection Object (CRUD)

ApiKey

Key: id RBAC: TenantAdmin+
11 Properties

Immutable, RBAC- and CIDR-restricted Scoped API Key (smk_<id>_<secret>) for /api/v1/send, SCIM 2.0, or sharpmail-cli.

GET /api/admin/cli/objects/ApiKey Lists active API keys (secret omitted)
POST /api/admin/cli/objects/ApiKey Mints a new API key and returns apiKey (smk_...) once
DELETE /api/admin/cli/objects/ApiKey/{id} Revokes the API key immediately
{ } Object Schema & Typed Properties application/json · camelCase
├─ id guid READ-ONLY
Default: UUIDv7
Unique key UUID (used to revoke via DELETE).
├─ apiKey string CREATE-ONLY
Default: smk_<id>_<secret>
Full Bearer token returned ONLY once upon creation.
├─ label string REQUIRED
Human-readable label (e.g. "Ansible GitOps" or "Shopware 6").
├─ role string OPTIONAL
Default: TenantAdmin
Privilege scope (User is strictly restricted to POST /api/v1/send).
Enum:"User""ComplianceAuditor""TenantAdmin""ServerAdmin"
├─ senderAddress string OPTIONAL
Authorized sender address (required when role="User").
├─ defaultCategory string OPTIONAL
Default: transactional
Default send category for this key.
Enum:"critical""transactional""notification""marketing"
├─ allowedCidrs string[] OPTIONAL
Default: [] (Alle IPs)
Allowed source IPv4/IPv6 CIDR networks.
├─ expiresInDays integer WRITE-ONLY (SECRET)
Default: null (Kein Ablauf)
Optional automatic expiration in days from creation.
├─ expiresAtUtc datetime READ-ONLY
Computed UTC expiration timestamp.
├─ outboundDailyLimit integer OPTIONAL
Default: 10000
Daily outbound send limit for this key.
├─ isActive boolean READ-ONLY
Default: true
Active status.
{
  "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 / sharpmail-cli erstellen:
sharpmail-cli create ApiKey \
  --set label="GitLab CI / Ansible" \
  --set role=TenantAdmin \
  --set allowedCidrs=10.20.0.0/16 \
  --set expiresInDays=90

# Schlüssel widerrufen:
sharpmail-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()!;
Collection Object (CRUD)

Route

Key: domain RBAC: ServerAdmin+
10 Properties

Per-domain outbound SMTP routing or TLS certificate exception (e.g. StartTlsIgnoreCert for partner MX hosts with mismatched certificates, or smart-host connector).

GET /api/admin/cli/objects/Route Lists all custom outbound routes
POST /api/admin/cli/objects/Route Creates a custom domain route or TLS override
PATCH /api/admin/cli/objects/Route/{domain} Updates target host, port, or TLS mode
DELETE /api/admin/cli/objects/Route/{domain} Deletes the custom route
{ } Object Schema & Typed Properties application/json · camelCase
├─ domain string PRIMARY KEY
Destination recipient domain (e.g. "neff.me" or "*.partner-holding.eu").
├─ targetHost string OPTIONAL
Default: "" (Auto DNS-MX)
Relay hostname or IP. Leave empty to resolve the destination MX via DNS automatically.
├─ targetPort integer OPTIONAL
Default: 25
Destination TCP port (25, 587, or 465).
├─ tlsMode string OPTIONAL
Default: StartTlsOptional
Outbound TLS and X.509 validation mode for this domain.
Enum:"StartTlsOptional""StartTlsRequired""StartTlsIgnoreCert""ImplicitTls""ImplicitTlsIgnoreCert""None"
├─ username string OPTIONAL
Optional SMTP AUTH username.
├─ password string WRITE-ONLY (SECRET)
Optional SMTP AUTH password.
├─ hasPassword boolean READ-ONLY
Default: false
Indicates whether a password is stored.
├─ clearPassword boolean WRITE-ONLY (SECRET)
Default: false
Set true to clear stored password.
├─ description string OPTIONAL
Admin audit note.
├─ enabled boolean OPTIONAL
Default: true
Enable or pause route.
{
  "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:
sharpmail-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:
sharpmail-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
});
Singleton Policy

TransactionalSend (Singleton)

Key: singleton RBAC: TenantAdmin+
11 Properties

Governs progressive 28-day IP warming, message categories, and per-recipient-provider hourly/daily quotas (Google, Microsoft, Yahoo/AOL, German ISPs, iCloud, *).

GET /api/admin/cli/objects/TransactionalSend/singleton Gets active IP warming & provider quota policy
PATCH /api/admin/cli/objects/TransactionalSend/singleton Updates warming day, preset, or provider quotas
{ } Object Schema & Typed Properties application/json · camelCase
├─ enabled boolean OPTIONAL
Default: true
Enables category and provider quota governance.
├─ warmingEnabled boolean OPTIONAL
Default: false
Enables progressive daily IP warming ramp.
├─ startAtWarmingDay integer WRITE-ONLY (SECRET)
Default: 1
Jumps or resets warming schedule to day N (1..365).
├─ currentWarmingDay integer READ-ONLY
Current active day in warming schedule.
├─ currentWarmingPercent integer READ-ONLY
Current active percentage of target provider quotas.
├─ warmingDailyRampPercents integer[] OPTIONAL
Default: [5,7,10,...,100]
Daily percentage array for the warming ramp.
├─ maxDeferHours integer OPTIONAL
Default: 48
Maximum lookahead window in hours for DeferQueue pacing.
├─ defaultCategory string OPTIONAL
Default: transactional
Fallback category when omitted in API calls.
Enum:"critical""transactional""notification""marketing"
├─ preset string WRITE-ONLY (SECRET)
One-step preset selector.
Enum:"warming_28d""warming_14d""production_100"
├─ categories CategoryPolicy[] OPTIONAL
Default: 4 Kategorien
Array of category policy objects.
├─ providers ProviderQuota[] OPTIONAL
Default: 6 Provider-Gruppen
Array of recipient-provider quota definitions.
{
  "enabled": true,
  "warmingEnabled": true,
  "startAtWarmingDay": 1,
  "maxDeferHours": 48,
  "defaultCategory": "transactional",
  "preset": "warming_28d"
}
# 28-Tage IP-Warming aktivieren:
sharpmail-cli update TransactionalSend --set preset=warming_28d

# Direkt auf Warming-Tag 14 vorspringen:
sharpmail-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 });
Singleton Policy

ReputationShield (Singleton)

Key: singleton RBAC: TenantAdmin+
20 Properties

Optional outbound reputation protection: automatic bounce/complaint suppression list, RFC 8058 One-Click Unsubscribe, bounce circuit breaker, adaptive 421 ISP backoff, and HMAC-SHA256 webhooks.

GET /api/admin/cli/objects/ReputationShield/singleton Gets current Reputation Shield configuration
PATCH /api/admin/cli/objects/ReputationShield/singleton Updates protection flags or applies a preset
{ } Object Schema & Typed Properties application/json · camelCase
├─ preset string WRITE-ONLY (SECRET)
Applies a complete protection profile in one step.
Enum:"off""recommended""strict_bulk"
├─ enableSuppressionPreCheck boolean OPTIONAL
Default: false
Filters suppressed addresses pre-send.
├─ enforceSuppressionOnSmtpRelay boolean OPTIONAL
Default: false
Also enforces suppression list on SMTP submission.
├─ allSuppressedBehavior string OPTIONAL
Default: reject_422
Response mode when all recipients are suppressed.
Enum:"reject_422""accept_noop"
├─ autoSuppressHardBounces boolean OPTIONAL
Default: false
Automatically suppresses 5xx permanent hard bounces.
├─ hardBounceSuppressionDays integer OPTIONAL
Default: 180
Retention days for hard-bounce suppressions.
├─ autoSuppressConsecutiveSoftBounces boolean OPTIONAL
Default: false
Escalates repeated 4xx soft bounces to suppression list.
├─ softBounceEscalationThreshold integer OPTIONAL
Default: 5
Consecutive soft bounces before suppression.
├─ autoSuppressFblComplaints boolean OPTIONAL
Default: false
Parses inbound RFC 5965 ARF abuse reports automatically.
├─ enableOneClickUnsubscribe boolean OPTIONAL
Default: false
Injects DKIM-signed RFC 8058 List-Unsubscribe headers.
├─ oneClickUnsubscribeCategories string[] OPTIONAL
Default: ["marketing","notification"]
Categories receiving RFC 8058 unsubscribe headers.
├─ enableBounceCircuitBreaker boolean OPTIONAL
Default: false
Pauses non-critical sends if 24h bounce/complaint rate spikes.
├─ maxHardBouncePercent number OPTIONAL
Default: 5.0
24h hard-bounce rate ceiling in percent.
├─ maxComplaintPercent number OPTIONAL
Default: 0.1
24h ARF complaint rate ceiling in percent.
├─ allowCriticalWhenTripped boolean OPTIONAL
Default: true
Allows critical 2FA mail even when circuit breaker is tripped.
├─ enableAdaptiveIspBackoff boolean OPTIONAL
Default: false
Automatic cooldown when remote MX returns 421/451 throttling.
├─ ispCooldownMinutes integer OPTIONAL
Default: 15
Cooldown duration in minutes.
├─ webhookEnabled boolean OPTIONAL
Default: false
Enables HMAC-SHA256 signed webhooks.
├─ webhookUrl string OPTIONAL
Destination HTTPS URL for webhooks.
├─ webhookSecret string WRITE-ONLY (SECRET)
HMAC-SHA256 secret for X-SharpMail-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/sharpmail"
}
# Empfohlenen Reputationsschutz aktivieren:
sharpmail-cli update ReputationShield --set preset=recommended

# Webhook-Ziel konfigurieren:
sharpmail-cli update ReputationShield \
  --set webhookEnabled=true \
  --set webhookUrl=https://erp.firma.de/webhooks/sharpmail \
  --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" });
Singleton Policy

SpamGuard (Singleton)

Key: singleton RBAC: ServerAdmin+
15 Properties

Multi-stage inbound defense: SPF/DKIM/DMARC/ARC verification, Smart Greylisting (/24 IPv4 & /64 IPv6), online ML classifier (FTRL-Proximal), DNSBL zones, allow/blocklists, and ClamAV TCP scan.

GET /api/admin/cli/objects/SpamGuard/singleton Gets SpamGuard thresholds & training counters
PATCH /api/admin/cli/objects/SpamGuard/singleton Updates scores, DNSBLs, allowlists, or ClamAV in place
{ } Object Schema & Typed Properties application/json · camelCase
├─ enableEmailAuthChecks boolean OPTIONAL
Default: true
Verifies inbound SPF, DKIM, DMARC, and ARC.
├─ enableGreylisting boolean OPTIONAL
Default: true
Adaptive Smart Greylisting for unknown first-time senders.
├─ greylistRetryDelaySeconds integer OPTIONAL
Default: 240
Minimum retry delay in seconds (default: 240s).
├─ junkScoreThreshold number OPTIONAL
Default: 4.5
Score threshold for filing into the Junk folder.
├─ rejectScoreThreshold number OPTIONAL
Default: 9.0
Score threshold for hard SMTP 550 rejection.
├─ tagSubjectOnJunk boolean OPTIONAL
Default: false
Prepend subject prefix to Junk messages.
├─ subjectTagPrefix string OPTIONAL
Default: "[SPAM] "
Subject prefix string.
├─ enableStructuralHeuristics boolean OPTIONAL
Default: true
Evaluates MIME/HTML structural heuristics.
├─ dnsblZones string[] OPTIONAL
Default: ["bl.spamcop.net","ix.dnsbl.manitu.net"]
Queried DNSBL zones.
├─ dnsblHitScore number OPTIONAL
Default: 3.5
Score added per DNSBL hit.
├─ allowedSendersOrDomains string[] OPTIONAL
Default: []
Explicit sender email or domain allowlist.
├─ blockedSendersOrDomains string[] OPTIONAL
Default: []
Explicit sender email or domain blocklist.
├─ clamAvEnabled boolean OPTIONAL
Default: false
Enables ClamAV daemon TCP INSTREAM scanning.
├─ clamAvHost string OPTIONAL
Default: "127.0.0.1"
ClamAV daemon host or IP.
├─ clamAvPort integer OPTIONAL
Default: 3310
ClamAV daemon TCP port.
{
  "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:
sharpmail-cli update SpamGuard \
  --set allowedSendersOrDomains=datev.de,partner-spedition.de

# Schwellenwerte anpassen:
sharpmail-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 });
Singleton Policy

SmtpQueue (Singleton)

Key: singleton RBAC: ServerAdmin+
19 Properties

Controls the outbound MX delivery queue, worker concurrency, retry intervals, ISP throttling, outbound TLS validation, global smart-host, and inbound ESMTP limits.

GET /api/admin/cli/objects/SmtpQueue/singleton Gets all queue, TLS, and ESMTP settings
PATCH /api/admin/cli/objects/SmtpQueue/singleton Updates queue workers, retry schedule, or ESMTP limits in 0 ms
{ } Object Schema & Typed Properties application/json · camelCase
├─ outboundQueuePaused boolean OPTIONAL
Default: false
Pauses outbound MX delivery while continuing to accept mail.
├─ outboundWorkerConcurrency integer OPTIONAL
Default: 8
Number of parallel outbound delivery workers.
├─ maxDeliveryAttempts integer OPTIONAL
Default: 10
Maximum delivery attempts before permanent bounce.
├─ retryScheduleMinutes integer[] OPTIONAL
Default: [5,15,60,240,720]
Retry backoff schedule in minutes.
├─ maxConcurrentConnectionsPerMxDomain integer OPTIONAL
Default: 4
Max concurrent connections per destination MX domain.
├─ strictThrottleDomains string[] OPTIONAL
Default: ["t-online.de","gmx.de","web.de","yahoo.com"]
Domains subject to strict concurrency throttling.
├─ strictThrottleMaxConcurrency integer OPTIONAL
Default: 2
Max concurrent connections for strictThrottleDomains.
├─ outboundConnectTimeoutSeconds integer OPTIONAL
Default: 30
Outbound TCP/TLS connect timeout in seconds.
├─ outboundBindAddress string OPTIONAL
Default: "" (Auto)
Optional local source IP bind address.
├─ outboundUseStartTls boolean OPTIONAL
Default: true
Use STARTTLS on outbound MX connections.
├─ requireOutboundTls boolean OPTIONAL
Default: false
Abort delivery if remote MX does not offer TLS.
├─ outboundTlsCertValidation string OPTIONAL
Default: Opportunistic
Global outbound X.509 certificate validation mode.
Enum:"Opportunistic""IgnoreErrors""Strict"
├─ outboundSmartHost string OPTIONAL
Default: ""
Optional global upstream relay host.
├─ outboundSmartPort integer OPTIONAL
Default: 587
Global smart-host TCP port.
├─ maxMessageSizeMb long OPTIONAL
Default: 50
Global ESMTP SIZE limit in MiB.
├─ maxRecipientsPerTransaction integer OPTIONAL
Default: 100
Maximum RCPT TO commands per transaction.
├─ maxConnectionsPerIp integer OPTIONAL
Default: 20
Maximum simultaneous inbound connections per IP.
├─ tarpitDelayMs integer OPTIONAL
Default: 1500
Tarpit delay in ms on auth/command errors.
├─ requireTlsForAuth boolean OPTIONAL
Default: true
Requires TLS encryption before allowing 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:
sharpmail-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 });
Singleton Policy

TransportRules & Server (Singletons)

Key: singleton RBAC: ServerAdmin+
11 Properties

Organization-wide legal disclaimer (inserted prior to DKIM signing), global inbound Sieve script, Fail2Ban auto-ban thresholds, and canonical ServerHostName.

GET /api/admin/cli/objects/TransportRules/singleton Gets disclaimer, global Sieve, and auto-ban settings
PATCH /api/admin/cli/objects/TransportRules/singleton Updates transport rules in place
GET /api/admin/cli/objects/Server/singleton Gets ServerHostName, storage engine, queue depth, and license status
PATCH /api/admin/cli/objects/Server/singleton Updates canonical ServerHostName in 0 ms
{ } Object Schema & Typed Properties application/json · camelCase
├─ outboundDisclaimerEnabled boolean OPTIONAL
Default: false
Appends mandatory corporate footer to outbound messages.
├─ outboundDisclaimerExternalOnly boolean OPTIONAL
Default: true
Append footer only when sending to external domains.
├─ outboundDisclaimerText string OPTIONAL
Default: ""
Plain-text legal footer.
├─ outboundDisclaimerHtml string OPTIONAL
Default: ""
HTML legal footer.
├─ inboundSystemSieve string OPTIONAL
Default: ""
Global RFC 5228 Sieve script executed before user scripts.
├─ autoBanThreshold integer OPTIONAL
Default: 8
Failed logins before automatic IP ban.
├─ autoBanDurationMinutes integer OPTIONAL
Default: 30
Automatic IP ban duration in minutes.
├─ serverHostName string OPTIONAL
Default: mail.<domain>
Canonical EHLO, TLS, and Autodiscover FQDN (Object: Server).
├─ storageProvider string READ-ONLY
Default: Sqlite | SqlServer | Postgres
Active storage engine (Object: Server).
├─ activeQueueCount integer READ-ONLY
Default: 0
Current outbound queue count (Object: Server).
├─ licenseState string READ-ONLY
Default: EnterpriseActive
License state (Object: 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:
sharpmail-cli update TransportRules \
  --set outboundDisclaimerEnabled=true \
  --set autoBanThreshold=8

# Kanonischen Server-Hostnamen abfragen oder setzen:
sharpmail-cli get Server
sharpmail-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")}");