Standalone SMTP gateway for Personal Cloud Server (PCS) deployments. This service receives emails from containerized applications (Vaultwarden, Nextcloud, etc.) and forwards them over HTTPS to a relay backend (the orchestrator email API) for delivery via SendGrid.
App (Vaultwarden, Nextcloud, etc.)
│
│ SMTP (port 587)
↓
smtp container (this service)
│
│ HTTPS API call
↓
Relay backend (orchestrator)
│
↓
SendGrid → Recipient
- SMTP Relay: Accepts SMTP connections on port 587
- Email Parsing: Full RFC-compliant MIME email parsing with inline image support
- API Forwarding: Forwards emails to the relay backend with JWT authentication
- Network Isolation: Runs in private Docker network (pcs)
- Multi-platform: Supports linux/amd64 and linux/arm64
- Lightweight: ~20MB Alpine-based Docker image
| Variable | Required | Default | Description |
|---|---|---|---|
RELAY_CREDENTIAL |
Yes | - | The credential the relay verifies. Explicit mode: an opaque bearer token (a JWT on Yundera). Provider mode (nsl): the PCS provider string backend_url,userid,signature — the gateway derives the endpoint and forwards userid:signature. |
RELAY_ENDPOINT_URL |
Conditional | - | Base URL of the relay backend's email API (gateway POSTs to {url}/email/send). Required in explicit mode; optional in provider mode, where it defaults to {backend_url}/router/api. |
SMTP_PORT |
No | 587 |
SMTP listening port |
Provider mode is detected automatically: a
RELAY_CREDENTIALwith exactly three comma-separated fields (backend_url,userid,signature) is treated as a provider string. A JWT contains no commas, so it always uses explicit mode.
services:
smtp:
image: ghcr.io/yundera/mail-gateway:latest
container_name: smtp
hostname: smtp
restart: unless-stopped
environment:
RELAY_CREDENTIAL: "${RELAY_CREDENTIAL}"
RELAY_ENDPOINT_URL: "${RELAY_ENDPOINT_URL}"
SMTP_PORT: "587"
expose:
- "587"
networks:
- pcs
networks:
pcs:
name: pcsApps running in the same Docker network can connect to the SMTP service using the hostname smtp.
SMTP_HOST=smtp
SMTP_PORT=587
SMTP_FROM=vaultwarden@yourdomain.com
SMTP_SECURITY=off # No TLS needed within Docker networkIn Nextcloud admin settings:
- Server address: smtp
- Port: 587
- Encryption: None/STARTTLS
- Network Isolation: Service only accepts connections from the private
pcsDocker network - No Public Exposure: SMTP port is NOT exposed to the internet
- JWT Authentication: All API calls to orchestrator are authenticated with JWT
- Rate Limiting: Orchestrator enforces rate limits (100 emails/hour per user)
docker build -t mail-gateway .docker run --rm \
-e RELAY_CREDENTIAL="your-credential" \
-e RELAY_ENDPOINT_URL="https://your-relay.example.com/service/pcs" \
-p 587:587 \
mail-gateway# Send a test email using telnet
telnet localhost 587
> EHLO test
> MAIL FROM:<test@example.com>
> RCPT TO:<recipient@example.com>
> DATA
> Subject: Test Email
>
> This is a test email body.
> .
> QUITThis service is automatically deployed to PCS instances via the docker-compose.yml template shipped with the mesh-router installer.
The service is automatically built and published to GitHub Container Registry on:
- Push to
mainbranch →latesttag - Version tags (e.g.,
v1.0.0) → version-specific tags
Check logs:
docker logs smtpCommon issues:
- Missing
RELAY_CREDENTIALenvironment variable - Port 587 already in use
- Network connectivity to orchestrator
- Check SMTP service logs:
docker logs smtp - Verify orchestrator URL is correct
- Check JWT token is valid
- Verify app is configured to use
smtpas hostname - Check orchestrator logs for API errors
Copyright Yundera Team