Skip to main content

mailaas: SMTP Relay PaaS Plugin for MetaPaaS

exim4 SMTP submission server packaged as a MetaPaaS plugin, following the same pattern as metapaas_s3.

Architecture

metapaas-cp
└── mail plugin (exordos_paas_mail)
    ├── CP: MailInstance + MailAccount models, REST API, migrations
    ├── infra_builder: CoreInfraBuilder → NodeSet + Config on core
    └── paas_builder: MailInstanceBuilder → MailInstanceNode → DP agent

mailaas-dp-<uuid> (VM)
└── exim4 (SMTP 25/465/587 — STARTTLS + auth)
    ├── /etc/exordos_metapaas/mail.env  ← delivered by CP (MAIL_DOMAIN)
    ├── /etc/exim4/passwd               ← managed by DP agent (lsearch auth)
    └── exordos-universal-agent         ← MailCapabilityDriver

Quick Start

Build

make build \
  REPOSITORY=http://10.20.0.1:8080/exordos-elements \
  INDEX_URL=http://10.20.0.1:8080/simple/

Produces:

  • output/images/exordos-metapaas-mail-dp.raw.zst (DP image)
  • output/manifests/mailaas.yaml (element manifest)

Install on running metapaas

make install

PluginReconciler on metapaas-cp installs exordos_paas_mail via pip and activates the /v1/types/mail/ route.

Create Instance

curl -X POST http://metapaas-cp:8080/v1/types/mail/instances/ \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer <token>' \
  -d '{
    "name": "mail-prod",
    "project_id": "4d657461-0000-0000-0000-000000000002",
    "domain": "example.com",
    "cpu": 2,
    "ram": 2048,
    "disk_size": 20,
    "version": "/v1/types/mail/versions/<version-uuid>"
  }'

Create SMTP Account

# Generate SHA512-crypt hash (compatible with exim4 crypteq)
HASH=$(openssl passwd -6 "mypassword")

curl -X POST http://metapaas-cp:8080/v1/types/mail/instances/<uuid>/accounts/ \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer <token>' \
  -d "{
    \"username\": \"alice\",
    \"password_hash\": \"${HASH}\",
    \"project_id\": \"4d657461-0000-0000-0000-000000000002\",
    \"instance\": \"/v1/types/mail/instances/<uuid>\"
  }"

Within seconds the DP agent writes the account to /etc/exim4/passwd and reloads exim4. The user can then authenticate via SMTP AUTH (PLAIN/LOGIN over STARTTLS on port 587 or SMTPS on port 465).

Hashes stored with a Dovecot {SHA512-CRYPT} scheme prefix are accepted — the driver strips the prefix before writing to exim4's passwd file.

Configure DNS

For mail to be accepted by other servers you must publish a few DNS records for your domain (referred to below as $1, e.g. example.com).

  • DKIM — the key is generated on the node by the configure script. Once the instance is ACTIVE, read it from the API:

    curl -s http://metapaas-cp:8080/v1/types/mail/instances/<uuid> \
      -H 'Authorization: Bearer <token>' | jq -r '{dkim_selector, dkim_public_key}'
    

    Publish it as a TXT record at <dkim_selector>._domainkey.$1 (default selector: platform), with the dkim_public_key value as data. The raw record is also on the node at /etc/exim4/dkim/platform.txt.

  • SPF — name: @ (the domain itself), type: TXT, TTL: 3600, data: "v=spf1 ip4:YOUR_SERVER_IP/32 a mx ~all"

  • DMARC — name: _dmarc, type: TXT, TTL: 3600, data: "v=DMARC1; p=none; pct=100; adkim=s; aspf=s"

  • PTR — set the reverse record for your server IP to $1

  • MX — ensure an MX record exists (e.g. name: @, type: MX, data: $1)

API Endpoints

Method Path Description
POST /v1/types/mail/instances/ Create mail server
GET /v1/types/mail/instances/ List instances
GET /v1/types/mail/instances/<uuid> Get instance
PATCH /v1/types/mail/instances/<uuid> Update (cpu/ram/disk_size)
DELETE /v1/types/mail/instances/<uuid> Delete
GET /v1/types/mail/versions/ List DP image versions
POST /v1/types/mail/instances/<uuid>/accounts/ Create account
GET /v1/types/mail/instances/<uuid>/accounts/ List accounts
PATCH /v1/types/mail/instances/<uuid>/accounts/<uuid> Update (active, password_hash)
DELETE /v1/types/mail/instances/<uuid>/accounts/<uuid> Delete account

Field permissions

Field Create Read Update
domain RW RO RO
status RO RO
ipsv4 RO RO
dkim_public_key RO RO
dkim_selector RO RO
password_hash RW hidden RW
username RW RO RO
active RW RW RW

Repository Layout

.
├── exordos_paas_mail/
│   ├── constants.py          # MAIL_ENV_FILE, EXIM4_PASSWD_FILE paths
│   ├── models.py             # MailVersion, MailInstance, MailAccount (restalchemy)
│   ├── controllers.py        # REST controllers (gcl_iam policy-based)
│   ├── routes.py             # Route tree (instances/accounts, versions)
│   ├── definition.py         # MailDefinition (PaaSDefinition contract)
│   ├── infra_models.py       # MailInstance + infra (NodeSet + Config)
│   ├── infra_builder.py      # CoreInfraBuilder (creates VMs + delivers mail.env)
│   ├── paas_models.py        # MailInstanceNode (target resource for DP agent)
│   ├── paas_builder.py       # MailInstanceBuilder (maps accounts → DP payload)
│   ├── driver.py             # MailCapabilityDriver: writes /etc/exim4/passwd
│   ├── utils.py              # remove_nested_dm helper
│   ├── migrations/
│   │   ├── 0000-init-mail.py # Creates mail_versions, mail_instances, mail_accounts
│   │   └── 0001-drop-root-password.py
│   └── tests/
│       ├── unit/             # Unit tests (models, driver)
│       └── functional/       # E2E tests (prepare_env.py + SMTP auth tests)
├── exordos/
│   ├── exordos.yaml          # Build config (deps + elements + DP image)
│   ├── images/
│   │   ├── dp_install.sh     # Packer: install exim4 + configure script + agent
│   │   └── dp_bootstrap.sh   # First-boot: persistent disk + start configure service
│   └── manifests/
│       ├── mailaas.yaml.j2  # Element manifest: type reg + IAM + DP version
│       └── example_mail.yaml.j2  # Example consumer element
├── etc/
│   ├── systemd/
│   │   ├── exordos-metapaas-mail-configure.service  # Configures exim4 from mail.env
│   │   └── exordos-metapaas-mail-agent.service      # Universal agent (MailCapabilityDriver)
│   └── exordos_metapaas/
│       ├── logging.yaml
│       └── metapaas_mail_agent.conf
├── .github/workflows/
│   ├── tests.yaml            # Lint (ruff) on every push
│   └── func_tests.yaml       # Full e2e: bootstrap core + deploy + SMTP tests
├── pyproject.toml
├── tox.ini
└── Makefile

Development

make test          # Unit tests via tox
make lint          # ruff check
make format        # ruff format
make typecheck     # mypy
make functional    # E2E tests (needs live stand)

Running functional tests manually

python exordos_paas_mail/tests/functional/prepare_env.py \
  --metapaas-dir ../exordos_metapaas \
  --project-dir . \
  --output-dir /tmp/mail-build \
  --endpoint http://10.20.0.2:11010 \
  --username admin --password <pass>

# Use env vars printed by prepare_env.py, then:
tox -e py312-functional

Key differences from metapaas_s3

Aspect s3aas mailaas
DP software RustFS exim4 (SMTP relay)
Instance children Bucket, Policy, User, AccessKey Account
Replicas 1–16 Always 1
Config delivered rustfs.env mail.env (domain only)
DP auth state S3 access keys /etc/exim4/passwd (SHA512-crypt)
On-change systemctl restart rustfs systemctl restart mail-configure
DP agent state file s3_meta.json mail_meta.json
uuid5 name s3aas mailaas

References

  • MetaPaaS design: ../exordos_metapaas/DESIGN.md
  • How to build new PaaS: ../exordos_s3/HOW_TO_BUILD_NEW_PAAS.md
  • Working reference: ../exordos_s3/

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

exordos_mail-0.0.4.tar.gz (399.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

exordos_mail-0.0.4-py3-none-any.whl (42.5 kB view details)

Uploaded Python 3

File details

Details for the file exordos_mail-0.0.4.tar.gz.

File metadata

  • Download URL: exordos_mail-0.0.4.tar.gz
  • Upload date:
  • Size: 399.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for exordos_mail-0.0.4.tar.gz
Algorithm Hash digest
SHA256 ebf8280bd04347fae8850ff3906ce1e14777ff53e54ec7368afba18df4721921
MD5 6df8d6df5577c75f150cec9c8a2ca226
BLAKE2b-256 78daaa44cf0fac76eb899861d8a21f38963cd01a80ad96865f56db5f45eef66d

See more details on using hashes here.

Provenance

The following attestation bundles were made for exordos_mail-0.0.4.tar.gz:

Publisher: publish-to-pypi.yml on exordos/exordos_mail

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file exordos_mail-0.0.4-py3-none-any.whl.

File metadata

  • Download URL: exordos_mail-0.0.4-py3-none-any.whl
  • Upload date:
  • Size: 42.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for exordos_mail-0.0.4-py3-none-any.whl
Algorithm Hash digest
SHA256 47fe03d775fdaf4e4707f315a31fc550c79b0a5a439c4e2ee54011a96b949b86
MD5 0d252fed09b93400f0fbb2e9bd9502e0
BLAKE2b-256 f8605fe57a943c8e7fa1a6da7fd3799cbd44d9c8d4e61ddfd1cb7615c1b4f5da

See more details on using hashes here.

Provenance

The following attestation bundles were made for exordos_mail-0.0.4-py3-none-any.whl:

Publisher: publish-to-pypi.yml on exordos/exordos_mail

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.0.8

2 files

0.0.7

2 files

0.0.6

2 files

0.0.5

2 files

This release

0.0.4 This release

2 files

0.0.3

2 files

0.0.2

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page