Install
openclaw skills install stalwart-dokploy-resend-relaySet up Stalwart Mail Server on a new VPS via Dokploy, with default outbound delivery through Resend SMTP relay for environments where direct SMTP port 25 egress is blocked.
openclaw skills install stalwart-dokploy-resend-relayUse this skill to deploy a production-ready Stalwart server on a new VPS managed by Dokploy.
Default assumption:
25 is blocked by provider/networksmtp.resend.com:587This skill covers:
example.commail.example.comBefore any configuration changes, run all checks below.
dig +short MX <domain>
dig +short A mail.<domain>
Pass criteria:
mail.<domain> with valid prioritymail.<domain> resolves to VPS public IPIf fail:
On VPS:
docker ps --format '{{.Names}} {{.Image}}' | grep -i dokploy
Pass criteria:
If fail:
On VPS:
docker ps --format '{{.Names}} {{.Image}}' | grep -i stalwart
Pass criteria:
If fail:
Use this exact branching logic:
Only continue to next phases when all three preflight checks pass.
Add/verify these records:
mail A -> <VPS_PUBLIC_IP>@ MX priority 10 -> mail.<domain>@ TXT -> v=spf1 mx include:amazonses.com -all_dmarc TXT -> v=DMARC1; p=none;Notes:
send.<domain> MX/SPF/DKIM) if used.send.<domain> MX for sending workflows can coexist.stalwartlabs/stalwart:latest-alpine)25, 465, 587, 993, 8080, 443/etc/stalwart, /var/lib/stalwart, /opt/stalwart-mailIf bootstrap keeps resetting after restart, fix volume ownership:
sudo chown -R 2000:2000 /var/lib/docker/volumes/<stalwart-volume>/_data
Target settings:
mail.<domain><domain>Use Let’s Encrypt for mail.<domain>:
sudo certbot certonly --standalone -d mail.<domain> --non-interactive --agree-tos -m support@<domain>
Then import the cert into Stalwart certificate store and set as defaultCertificateId.
If the UI create form rejects the PEM with No certificates found in PEM, create the certificate through the JMAP x:Certificate/set endpoint instead, using the leaf certificate PEM and private key, then set x:SystemSettings.defaultCertificateId to the created certificate object ID and restart Stalwart so 465/993 pick up the new cert.
Verify:
openssl s_client -connect mail.<domain>:465 -servername mail.<domain> < /dev/null 2>/dev/null | openssl x509 -noout -subject -issuer -dates
openssl s_client -connect mail.<domain>:993 -servername mail.<domain> < /dev/null 2>/dev/null | openssl x509 -noout -subject -issuer -dates
Expected:
mail.<domain>Create at least:
admin@<domain>)support@<domain>)Verify auth from server side:
# IMAP auth test
openssl s_client -quiet -crlf -connect 127.0.0.1:<mapped-993> <<<'a1 LOGIN support@<domain> <password>'
# SMTP auth test
# AUTH PLAIN with base64(\0user\0pass)
When port 25 egress is blocked, do not use direct MX delivery route for outbound.
Configure in Stalwart:
relay (@type: Relay):smtp.resend.com587falseresend<RESEND_API_KEY>x:MtaOutboundStrategy route expression:else to 'relay'Resulting behavior:
Map host to Stalwart web service (container port 8080):
mail.<domain>//Admin UI URL:
https://mail.<domain>/admin/dig +short MX <domain>
dig +short A mail.<domain>
nc -zv mail.<domain> 993
nc -zv mail.<domain> 465
nc -zv mail.<domain> 25
IMAP/SMTP login works for support@<domain>.
Queue health:
x:QueuedMessage/get should not accumulate permanent TemporaryFailure entries.Scheduled too long, inspect route/worker status and restart service.support@<domain> and verify receiptUse manual settings (autodiscovery may fail):
mail.<domain> / 993 / SSL/TLS / Normal passwordmail.<domain> / 465 / SSL/TLS / Normal passwordIf direct outbound delivery remains blocked and Stalwart queue is not healthy, temporary fallback:
smtp.resend.com465 (SSL/TLS) or 587 (STARTTLS)resendchown volumes to stalwart user (2000:2000)x:SystemSettingsNo certificates found in PEM, use JMAP x:Certificate/set with the leaf PEM + private key, then restart StalwartNetwork unreachable (os error 101)Complete when:
https://mail.<domain>/admin/ openssupport@<domain> can authenticate over IMAP/SMTPsupport@<domain> is received