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.5.tar.gz (443.6 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.5-py3-none-any.whl (42.8 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: exordos_mail-0.0.5.tar.gz
  • Upload date:
  • Size: 443.6 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.5.tar.gz
Algorithm Hash digest
SHA256 3d653de9180d25686432e8b16ab1c65dc287abe2aa71acb9623b688e10a24d4b
MD5 46a794db3fd8704a2af3dd5d77fb6dbe
BLAKE2b-256 833982d32723a3ed606279c3feb36b54ce9294a509fb8f97dd1ed32f42dc01f8

See more details on using hashes here.

Provenance

The following attestation bundles were made for exordos_mail-0.0.5.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.5-py3-none-any.whl.

File metadata

  • Download URL: exordos_mail-0.0.5-py3-none-any.whl
  • Upload date:
  • Size: 42.8 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.5-py3-none-any.whl
Algorithm Hash digest
SHA256 5cd1be95920dbbfba76b0518652bbe6ab719d0d39d87d3ff226da57b74cf4d31
MD5 2e2b7c464b49f521a68756e458892ee1
BLAKE2b-256 23f6ce4fdd016a01426205dcc893e91bb7f1877683abf2700d19af743142ee8d

See more details on using hashes here.

Provenance

The following attestation bundles were made for exordos_mail-0.0.5-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

This release

0.0.5 This release

2 files

0.0.4

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