How Openship's Built-in Mail Server Handles DKIM, SPF, and DMARC Authentication

Openship automatically provisions a complete email authentication stack by generating 2048-bit DKIM keys, publishing SPF and DMARC DNS records, and validating them through an integrated DNS-scan service.

Openship (oblien/openship) ships with a production-ready mail server powered by iRedMail and amavisd-new that eliminates manual DNS configuration for transactional email. The platform handles the entire lifecycle of email authentication—from cryptographic key generation to real-time DNS validation—ensuring outbound messages pass modern anti-spam filters without manual TXT record management.

Architecture Overview

The mail authentication system operates through three distinct layers defined in the source code: provisioning, DNS record creation, and administration/validation.

Provisioning Layer

When a domain is added, the system initiates cryptographic provisioning via packages/core/src/mail-server/routing/build‑routes.ts (lines 109‑118). This layer executes amavisd‑new genrsa to create a 2048-bit RSA key pair, writing the private key to /var/lib/dkim/<domain>.pem and updating Amavis configuration at /etc/amavis/conf.d/50-user with a dkim_key directive.

DNS Record Management

The apps/api/src/modules/mail/mail-state.ts file (lines 203‑267) defines the PersistedDnsRecord interface that stores five record types: a, mx, spf, dkim, and dmarc. These records persist in the mail_state database table, creating a single source of truth for DNS configuration that survives container restarts.

Administration and Validation

Two services handle ongoing verification:

  • domain-dns.service.ts (lines 221‑242): Injects DKIM values into DNS payloads when domains are registered
  • dns-scan.service.ts (lines 295‑327): Periodically queries public DNS to verify TXT records match the persisted state, detecting truncation or misconfiguration

DKIM Key Generation and Configuration

DomainKeys Identified Mail (DKIM) signing requires a private key stored on the server and a corresponding public key published via DNS.

When you execute openship mail add-domain <domain> or use the dashboard, the provisionDomainDkim function in apps/api/src/modules/mail/mail.service.ts (lines 1020‑1034) performs the following:


# Executed internally by the provisioning service

amavisd genrsa /var/lib/dkim/example.com.pem 2048

The service then parses the generated public key and constructs the DKIM TXT record value. The private key remains on the filesystem at /var/lib/dkim/<domain>.pem, while Amavis configuration (50-user) receives an entry mapping the domain to its key path:

dkim_key('example.com', 'dkim', '/var/lib/dkim/example.com.pem');

This enables enable_dkim_signing = 1 in Amavis, automatically signing all outbound mail headers with the domain-specific key.

DNS Record Specifications

Openship generates three mandatory TXT records for complete email authentication, accessible via the GET /mail/dns/:domain endpoint defined in apps/api/src/modules/mail/mail.service.ts (lines 960‑1000).

DKIM Records

The DKIM TXT record uses the selector dkim and follows standard format:


Name:  dkim._domainkey.example.com
Type:  TXT
Value: v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC...

The implementation in build-routes.ts constructs this value by base64-encoding the RSA public key and wrapping it with the DKIM version and key type identifiers.

SPF and DMARC Policies

SPF Record: Published at the root domain with a restrictive policy allowing only the server's A and MX records:


v=spf1 a mx -all

DMARC Record: Published at _dmarc.example.com with a strict rejection policy and aggregate reporting:


v=DMARC1; p=reject; rua=mailto:postmaster@example.com

Both records are generated as static strings in mail.service.ts (lines 960‑962) during the domain provisioning workflow, though administrators can override these defaults through the database if specific configurations are required.

Validation and API Integration

Openship continuously monitors DNS propagation to prevent email delivery failures caused by missing or malformed records.

DNS Verification Service

The dns-scan.service.ts module implements a background worker that compares the PersistedDnsRecord values stored in the database against live DNS queries. If the DKIM public key retrieved from dig TXT dkim._domainkey.<domain> does not match the stored fingerprint, the service updates the error field in the mail state record and surfaces a warning in the dashboard.

API and CLI Interfaces

Administrators can retrieve current DNS requirements through multiple interfaces:

REST API (apps/dashboard/src/lib/api/mail.ts, line 153):

curl https://api.openship.example.com/mail/dns/example.com

Returns a JSON payload containing all five record types (a, mx, spf, dkim, dmarc) with their exact values.

Command Line:

openship mail dns example.com

This command outputs a markdown-formatted table suitable for copy-paste into DNS provider consoles, implemented in apps/cli/src/commands/mail.ts (line 87).

Summary

  • Automatic DKIM provisioning: Generates 2048-bit RSA keys via amavisd-new, stores them in /var/lib/dkim/, and configures Amavis (50-user) for signing.
  • Complete DNS coverage: Creates DKIM (dkim._domainkey), SPF (root domain), and DMARC (_dmarc) TXT records with secure defaults (p=reject).
  • Persistent state management: Stores record values in the mail_state table using the PersistedDnsRecord schema for durability.
  • Continuous validation: The DNS-scan service verifies public records against stored values, detecting truncation or propagation delays.
  • Multi-interface access: Retrieve records via REST API (GET /mail/dns/:domain) or CLI (openship mail dns).

Frequently Asked Questions

How does Openship generate DKIM keys?

Openship calls amavisd genrsa /var/lib/dkim/<domain>.pem to create a 2048-bit RSA key pair, then registers the private key path in /etc/amavis/conf.d/50-user while extracting the public component for DNS publication. This process is triggered automatically when adding a domain through the CLI or dashboard.

What DNS records does Openship create for email authentication?

The system produces three TXT records: a DKIM record at dkim._domainkey.<domain> containing the RSA public key, an SPF record at the root domain with v=spf1 a mx -all, and a DMARC record at _dmarc.<domain> with v=DMARC1; p=reject; rua=mailto:postmaster@<domain>.

How can I verify my DNS records are correctly configured?

Use the built-in DNS scan service defined in apps/api/src/modules/mail/admin/dns-scan.service.ts, which periodically checks public DNS against the persisted mail_state records. Alternatively, query the GET /mail/dns/:domain endpoint or run openship mail dns <domain> to view the expected values and compare them against your DNS provider's configuration.

Where are the DKIM keys stored on the server?

Private keys are stored as PEM files at /var/lib/dkim/<domain>.pem with restrictive filesystem permissions, while the Amavis configuration at /etc/amavis/conf.d/50-user contains the dkim_key directives mapping domains to their respective key paths. Public keys are not stored on disk but are generated on-demand for DNS responses.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →