benethos-mailbox-service 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- benethos_mailbox_service-0.1.0/.gitignore +56 -0
- benethos_mailbox_service-0.1.0/LICENSE +21 -0
- benethos_mailbox_service-0.1.0/PKG-INFO +250 -0
- benethos_mailbox_service-0.1.0/README.md +209 -0
- benethos_mailbox_service-0.1.0/pyproject.toml +82 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/__init__.py +12 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/__main__.py +256 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/common/__init__.py +6 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/common/clock.py +10 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/common/ids.py +11 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/common/opaque.py +28 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/config.py +88 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/__init__.py +7 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/discovery/__init__.py +51 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/discovery/autoconfig.py +156 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/discovery/base.py +37 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/discovery/dns.py +41 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/discovery/isp.py +43 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/discovery/ispdb.py +32 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/discovery/mx.py +54 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/discovery/placeholders.py +23 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/discovery/presets.json +263 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/discovery/presets.py +101 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/discovery/suffix.py +24 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/files.py +21 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/http/__init__.py +29 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/http/api.py +91 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/http/base.py +52 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/http/safe.py +150 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/mail/__init__.py +6 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/mail/compose.py +250 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/mail/convert.py +78 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/mail/fields.py +35 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/mail/parse.py +123 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/mail/text.py +80 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/models/__init__.py +93 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/models/accounts.py +45 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/models/audit.py +37 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/models/batch.py +51 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/models/discovery.py +99 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/models/folders.py +66 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/models/messages.py +163 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/models/paging.py +33 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/models/sending.py +78 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/models/users.py +63 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/providers/__init__.py +178 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/providers/base.py +178 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/providers/guard.py +129 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/providers/imap/__init__.py +7 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/providers/imap/mappers.py +290 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/providers/imap/provider.py +790 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/providers/memory/__init__.py +7 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/providers/memory/provider.py +298 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/providers/microsoft/__init__.py +9 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/providers/microsoft/mappers.py +217 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/providers/microsoft/provider.py +555 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/providers/microsoft/signin.py +41 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/providers/protocols/__init__.py +8 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/providers/protocols/imap.py +583 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/providers/protocols/oauth.py +261 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/providers/protocols/smtp.py +168 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/providers/protocols/transport.py +28 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/providers/ratelimit.py +57 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/providers/rules.py +116 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/providers/sender.py +76 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/secrets/__init__.py +28 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/secrets/backup.py +121 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/secrets/cipher.py +43 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/secrets/keys.py +132 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/secrets/vault.py +170 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/storage/__init__.py +145 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/storage/accounts.py +72 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/storage/credentials.py +73 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/storage/idempotency.py +51 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/storage/index.py +141 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/storage/sends.py +61 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/storage/sqlite/__init__.py +27 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/storage/sqlite/accounts.py +80 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/storage/sqlite/credentials.py +76 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/storage/sqlite/database.py +325 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/storage/sqlite/idempotency.py +48 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/storage/sqlite/index.py +142 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/storage/sqlite/rows.py +39 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/storage/sqlite/sends.py +79 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/storage/sqlite/users.py +127 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/storage/table.py +77 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/storage/users.py +85 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/domain/__init__.py +7 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/domain/access.py +233 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/domain/accounts.py +267 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/domain/adapters.py +156 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/domain/auth.py +148 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/domain/calls.py +236 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/domain/discovery.py +386 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/domain/idempotency.py +88 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/domain/locks.py +29 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/domain/mailbox.py +405 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/domain/merge.py +94 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/domain/oauth.py +190 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/domain/outgoing.py +395 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/domain/paging.py +17 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/domain/permissions.py +141 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/domain/replies.py +98 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/domain/sending.py +162 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/domain/sync.py +218 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/domain/throttle.py +105 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/domain/users.py +306 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/domain/worker.py +126 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/errors.py +128 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/main.py +234 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/py.typed +0 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/__init__.py +53 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/api/__init__.py +56 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/api/deps.py +101 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/api/errors.py +68 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/api/routes/__init__.py +1 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/api/routes/accounts.py +62 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/api/routes/discovery.py +27 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/api/routes/health.py +12 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/api/routes/mailbox.py +302 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/api/routes/messages.py +37 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/api/routes/oauth.py +38 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/api/routes/users.py +120 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/api/schemas.py +177 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/errors.py +43 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/__init__.py +137 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/deps.py +50 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/effective.py +54 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/errors.py +23 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/forms.py +47 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/grants.py +137 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/mailform.py +210 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/rights.py +21 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/routes/__init__.py +2 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/routes/accounts.py +206 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/routes/compose.py +66 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/routes/drafts.py +143 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/routes/folders.py +95 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/routes/home.py +23 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/routes/login.py +92 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/routes/mail.py +212 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/routes/messages.py +114 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/routes/oauth.py +84 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/routes/sends.py +64 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/routes/users.py +264 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/session.py +119 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/static/css/app.css +400 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/static/js/app.js +32 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/static/vendor/htmx/README.md +2 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/static/vendor/htmx/htmx.min.js +1 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/bare.html +22 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/base.html +34 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/components/connection.html +50 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/components/grants.html +75 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/components/ui.html +72 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/pages/account.html +68 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/pages/account_mail.html +107 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/pages/account_new.html +126 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/pages/accounts.html +37 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/pages/compose.html +102 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/pages/drafts.html +12 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/pages/error.html +7 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/pages/home.html +46 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/pages/login.html +18 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/pages/mail.html +27 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/pages/message.html +86 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/pages/oauth_bounce.html +11 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/pages/role.html +37 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/pages/roles.html +51 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/pages/sends.html +64 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/pages/user.html +141 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/pages/user_new.html +28 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/pages/users.html +39 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/partials/account_status.html +5 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/partials/flash.html +5 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/partials/mail_search.html +26 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/partials/message_list.html +42 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/partials/sidebar.html +24 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates.py +143 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/responses.py +18 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/search.py +33 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/services.py +67 -0
- benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/urls.py +28 -0
- benethos_mailbox_service-0.1.0/tests/conftest.py +173 -0
- benethos_mailbox_service-0.1.0/tests/graph_fake.py +328 -0
- benethos_mailbox_service-0.1.0/tests/imap_fake.py +423 -0
- benethos_mailbox_service-0.1.0/tests/provider_ops.py +26 -0
- benethos_mailbox_service-0.1.0/tests/smtp_fake.py +77 -0
- benethos_mailbox_service-0.1.0/tests/test_access.py +137 -0
- benethos_mailbox_service-0.1.0/tests/test_account_hosts.py +123 -0
- benethos_mailbox_service-0.1.0/tests/test_account_status.py +62 -0
- benethos_mailbox_service-0.1.0/tests/test_accounts.py +90 -0
- benethos_mailbox_service-0.1.0/tests/test_across_accounts.py +195 -0
- benethos_mailbox_service-0.1.0/tests/test_architecture.py +194 -0
- benethos_mailbox_service-0.1.0/tests/test_auth.py +201 -0
- benethos_mailbox_service-0.1.0/tests/test_backup.py +264 -0
- benethos_mailbox_service-0.1.0/tests/test_batch.py +167 -0
- benethos_mailbox_service-0.1.0/tests/test_cli.py +77 -0
- benethos_mailbox_service-0.1.0/tests/test_delete.py +98 -0
- benethos_mailbox_service-0.1.0/tests/test_discovery.py +590 -0
- benethos_mailbox_service-0.1.0/tests/test_discovery_parts.py +469 -0
- benethos_mailbox_service-0.1.0/tests/test_discovery_sources.py +279 -0
- benethos_mailbox_service-0.1.0/tests/test_draft_reference.py +64 -0
- benethos_mailbox_service-0.1.0/tests/test_drafts.py +458 -0
- benethos_mailbox_service-0.1.0/tests/test_folders.py +212 -0
- benethos_mailbox_service-0.1.0/tests/test_health_and_auth.py +46 -0
- benethos_mailbox_service-0.1.0/tests/test_html_mail.py +99 -0
- benethos_mailbox_service-0.1.0/tests/test_idempotency.py +245 -0
- benethos_mailbox_service-0.1.0/tests/test_ids.py +15 -0
- benethos_mailbox_service-0.1.0/tests/test_imap.py +471 -0
- benethos_mailbox_service-0.1.0/tests/test_imap_encodings.py +148 -0
- benethos_mailbox_service-0.1.0/tests/test_imap_probe.py +68 -0
- benethos_mailbox_service-0.1.0/tests/test_imap_sync.py +183 -0
- benethos_mailbox_service-0.1.0/tests/test_index_storage.py +156 -0
- benethos_mailbox_service-0.1.0/tests/test_mailbox.py +79 -0
- benethos_mailbox_service-0.1.0/tests/test_microsoft.py +472 -0
- benethos_mailbox_service-0.1.0/tests/test_move.py +120 -0
- benethos_mailbox_service-0.1.0/tests/test_oauth.py +507 -0
- benethos_mailbox_service-0.1.0/tests/test_openapi.py +67 -0
- benethos_mailbox_service-0.1.0/tests/test_packaging.py +114 -0
- benethos_mailbox_service-0.1.0/tests/test_permissions.py +77 -0
- benethos_mailbox_service-0.1.0/tests/test_ratelimit.py +56 -0
- benethos_mailbox_service-0.1.0/tests/test_reply.py +389 -0
- benethos_mailbox_service-0.1.0/tests/test_search.py +132 -0
- benethos_mailbox_service-0.1.0/tests/test_secrets.py +381 -0
- benethos_mailbox_service-0.1.0/tests/test_send.py +254 -0
- benethos_mailbox_service-0.1.0/tests/test_send_constraints.py +452 -0
- benethos_mailbox_service-0.1.0/tests/test_smtp.py +280 -0
- benethos_mailbox_service-0.1.0/tests/test_sqlite.py +210 -0
- benethos_mailbox_service-0.1.0/tests/test_storage.py +181 -0
- benethos_mailbox_service-0.1.0/tests/test_sync.py +371 -0
- benethos_mailbox_service-0.1.0/tests/test_throttle.py +190 -0
- benethos_mailbox_service-0.1.0/tests/test_ui.py +270 -0
- benethos_mailbox_service-0.1.0/tests/test_ui_accounts.py +187 -0
- benethos_mailbox_service-0.1.0/tests/test_ui_mail.py +135 -0
- benethos_mailbox_service-0.1.0/tests/test_ui_oauth.py +229 -0
- benethos_mailbox_service-0.1.0/tests/test_ui_sends.py +84 -0
- benethos_mailbox_service-0.1.0/tests/test_ui_users.py +409 -0
- benethos_mailbox_service-0.1.0/tests/test_ui_write.py +379 -0
- benethos_mailbox_service-0.1.0/tests/test_update.py +160 -0
- benethos_mailbox_service-0.1.0/tests/test_users.py +305 -0
- benethos_mailbox_service-0.1.0/tests/test_verify.py +135 -0
- benethos_mailbox_service-0.1.0/tests/test_worker.py +183 -0
- benethos_mailbox_service-0.1.0/tests/ui_helpers.py +44 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Virtual environment
|
|
2
|
+
.venv/
|
|
3
|
+
venv/
|
|
4
|
+
|
|
5
|
+
# Python
|
|
6
|
+
__pycache__/
|
|
7
|
+
*.py[cod]
|
|
8
|
+
*.egg-info/
|
|
9
|
+
.eggs/
|
|
10
|
+
build/
|
|
11
|
+
dist/
|
|
12
|
+
|
|
13
|
+
# Caching / coverage
|
|
14
|
+
.pytest_cache/
|
|
15
|
+
.mypy_cache/
|
|
16
|
+
.ruff_cache/
|
|
17
|
+
.cache/
|
|
18
|
+
*.sqlite
|
|
19
|
+
.coverage
|
|
20
|
+
.coverage.*
|
|
21
|
+
htmlcov/
|
|
22
|
+
coverage.xml
|
|
23
|
+
|
|
24
|
+
# IDE / OS
|
|
25
|
+
.vscode/
|
|
26
|
+
.idea/
|
|
27
|
+
.DS_Store
|
|
28
|
+
Thumbs.db
|
|
29
|
+
|
|
30
|
+
# Local configuration and secrets
|
|
31
|
+
.env
|
|
32
|
+
# config/: per package, only the templates are versioned
|
|
33
|
+
config/**
|
|
34
|
+
!config/**/
|
|
35
|
+
!config/*/.env.example
|
|
36
|
+
*.token.json
|
|
37
|
+
# containers/secrets/: the master key of a container deployment
|
|
38
|
+
containers/secrets/
|
|
39
|
+
|
|
40
|
+
# Service data: the database holds encrypted credentials, backups the same.
|
|
41
|
+
# data/: per package, only the folders are versioned (.gitkeep)
|
|
42
|
+
data/**
|
|
43
|
+
!data/**/
|
|
44
|
+
*.db
|
|
45
|
+
*.db-journal
|
|
46
|
+
*.db-wal
|
|
47
|
+
*.db-shm
|
|
48
|
+
**/backups/**
|
|
49
|
+
!**/backups/**/
|
|
50
|
+
|
|
51
|
+
# Live checks: test server address and test accounts stay local
|
|
52
|
+
live/.env
|
|
53
|
+
|
|
54
|
+
# .gitkeep holds an empty folder and is kept wherever it is. Only works
|
|
55
|
+
# below folders ignored file by file (as above), not below an ignored folder.
|
|
56
|
+
!.gitkeep
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Benedikt Oswald
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: benethos-mailbox-service
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Self-hosted mail service: one REST API and a web UI for IMAP and Microsoft 365 / Outlook.com accounts, with users, rights and encrypted credentials.
|
|
5
|
+
Project-URL: Homepage, https://github.com/benethos-hub/mailbox/tree/main/packages/mailbox-service#readme
|
|
6
|
+
Project-URL: Repository, https://github.com/benethos-hub/mailbox
|
|
7
|
+
Project-URL: Issues, https://github.com/benethos-hub/mailbox/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/benethos-hub/mailbox/blob/main/CHANGELOG.md
|
|
9
|
+
Author: Benedikt Oswald
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: email,email-automation,fastapi,imap,mail,microsoft-365,microsoft-graph,multi-account,oauth2,openapi,outlook,rest-api,self-hosted,smtp
|
|
13
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
14
|
+
Classifier: Environment :: Web Environment
|
|
15
|
+
Classifier: Framework :: FastAPI
|
|
16
|
+
Classifier: Intended Audience :: Developers
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
23
|
+
Classifier: Topic :: Communications :: Email
|
|
24
|
+
Requires-Python: >=3.11
|
|
25
|
+
Requires-Dist: anyio>=4
|
|
26
|
+
Requires-Dist: cryptography>=44
|
|
27
|
+
Requires-Dist: defusedxml>=0.7
|
|
28
|
+
Requires-Dist: dnspython>=2.6
|
|
29
|
+
Requires-Dist: fastapi>=0.120
|
|
30
|
+
Requires-Dist: httpx>=0.28
|
|
31
|
+
Requires-Dist: imap-tools>=1.10
|
|
32
|
+
Requires-Dist: imapclient>=4.1.0
|
|
33
|
+
Requires-Dist: jinja2>=3.1
|
|
34
|
+
Requires-Dist: keyring>=25
|
|
35
|
+
Requires-Dist: publicsuffixlist>=1.0
|
|
36
|
+
Requires-Dist: pydantic-settings>=2.10
|
|
37
|
+
Requires-Dist: pydantic>=2.11
|
|
38
|
+
Requires-Dist: python-multipart>=0.0.20
|
|
39
|
+
Requires-Dist: uvicorn>=0.38
|
|
40
|
+
Description-Content-Type: text/markdown
|
|
41
|
+
|
|
42
|
+
# benethos-mailbox-service
|
|
43
|
+
|
|
44
|
+
[](https://github.com/benethos-hub/mailbox/actions/workflows/ci.yml)
|
|
45
|
+
[](https://pypi.org/project/benethos-mailbox-service/)
|
|
46
|
+
[](https://github.com/benethos-hub/mailbox/pkgs/container/benethos-mailbox-service)
|
|
47
|
+
[](https://pypi.org/project/benethos-mailbox-service/)
|
|
48
|
+
[](https://github.com/benethos-hub/mailbox/blob/main/LICENSE)
|
|
49
|
+
|
|
50
|
+
> **Pre-alpha, version 0.1.0.** Not ready for production use: the API,
|
|
51
|
+
> the stored data and the configuration may change without notice.
|
|
52
|
+
|
|
53
|
+
The Mailbox Service: one REST API (OpenAPI 3.1) for several mail
|
|
54
|
+
providers and accounts, with a configuration UI in the browser. It runs
|
|
55
|
+
permanently, holds the connections to the accounts, keeps their
|
|
56
|
+
credentials encrypted and syncs in the background. Scripts, apps and the
|
|
57
|
+
MCP server [`benethos-mailbox-mcp`](https://github.com/benethos-hub/mailbox/tree/main/packages/mailbox-mcp)
|
|
58
|
+
reach mail only through it, each with a token of its own.
|
|
59
|
+
|
|
60
|
+
What the project is for: [the repository's README](https://github.com/benethos-hub/mailbox#readme).
|
|
61
|
+
|
|
62
|
+
## Install
|
|
63
|
+
|
|
64
|
+
From PyPI, with [uv](https://docs.astral.sh/uv/) or pip:
|
|
65
|
+
|
|
66
|
+
```sh
|
|
67
|
+
uv tool install benethos-mailbox-service # or: pipx install benethos-mailbox-service
|
|
68
|
+
benethos-mailbox-service --version
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
`uvx benethos-mailbox-service ...` runs it without installing. In a clone of
|
|
72
|
+
the repository, every command below also works as
|
|
73
|
+
`uv run benethos-mailbox-service ...`.
|
|
74
|
+
|
|
75
|
+
The container image is `ghcr.io/benethos-hub/benethos-mailbox-service`. See
|
|
76
|
+
[Container](#container).
|
|
77
|
+
|
|
78
|
+
## First start
|
|
79
|
+
|
|
80
|
+
```sh
|
|
81
|
+
benethos-mailbox-service keys init # once: the keys; prints the recovery key
|
|
82
|
+
benethos-mailbox-service users create-admin # once: a user with every right; prints its token
|
|
83
|
+
benethos-mailbox-service serve
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
- `keys init` creates the master key in the operating system's credential
|
|
87
|
+
store and the data key in the database. It prints a **recovery key**
|
|
88
|
+
once. Keep it apart from the machine and its backups. Without it, a
|
|
89
|
+
database cannot be opened on another machine.
|
|
90
|
+
- `users create-admin` prints an API token once. Use it to sign in to the
|
|
91
|
+
UI, and send it as `Authorization: Bearer <token>` to the API.
|
|
92
|
+
- `serve` listens on `http://127.0.0.1:8080`:
|
|
93
|
+
- `/ui`: the configuration UI (sign in with the token)
|
|
94
|
+
- `/docs`: the interactive API documentation
|
|
95
|
+
- `/health`: open, for health checks
|
|
96
|
+
|
|
97
|
+
Then connect accounts in the UI (Accounts, Connect an account) or with
|
|
98
|
+
`POST /v1/accounts`. An IMAP account needs its address and an app
|
|
99
|
+
password. The service looks up the servers from the address. Microsoft
|
|
100
|
+
accounts sign in with OAuth and need an app registration first:
|
|
101
|
+
[docs/microsoft.md](https://github.com/benethos-hub/mailbox/blob/main/docs/microsoft.md).
|
|
102
|
+
|
|
103
|
+
## Where things live
|
|
104
|
+
|
|
105
|
+
The service works from the folder it is started in:
|
|
106
|
+
|
|
107
|
+
| What | Where |
|
|
108
|
+
|---|---|
|
|
109
|
+
| settings | the environment, or `config/benethos-mailbox-service/.env` (the environment wins) |
|
|
110
|
+
| the database | `data/benethos-mailbox-service/mailbox.db`, readable by its owner only |
|
|
111
|
+
| the master key | the OS credential store (keyring), or a file or variable (see `MAILBOX_SERVICE_KEY_PROVIDER`) |
|
|
112
|
+
|
|
113
|
+
A template for the settings file with every option:
|
|
114
|
+
[config/benethos-mailbox-service/.env.example](https://github.com/benethos-hub/mailbox/blob/main/config/benethos-mailbox-service/.env.example).
|
|
115
|
+
|
|
116
|
+
## Settings
|
|
117
|
+
|
|
118
|
+
| Setting | Default | Meaning |
|
|
119
|
+
|---|---|---|
|
|
120
|
+
| `MAILBOX_SERVICE_HOST`, `MAILBOX_SERVICE_PORT` | `127.0.0.1`, `8080` | where the service listens (`serve --host/--port` win) |
|
|
121
|
+
| `MAILBOX_SERVICE_PUBLIC_URL` | from each request | the address people reach the service at, e.g. behind a proxy. The OAuth redirect address is built from it. |
|
|
122
|
+
| `MAILBOX_SERVICE_FORWARDED_ALLOW_IPS` | `127.0.0.1` | behind a reverse proxy: its address, whose `X-Forwarded-*` headers give the client address, scheme and host |
|
|
123
|
+
| `MAILBOX_SERVICE_LOG_LEVEL` | `INFO` | |
|
|
124
|
+
| `MAILBOX_SERVICE_DATA_DIR` | `data/benethos-mailbox-service` | where the database lives |
|
|
125
|
+
| `MAILBOX_SERVICE_STORAGE` | `sqlite` | or `memory`, which keeps nothing |
|
|
126
|
+
| `MAILBOX_SERVICE_KEY_PROVIDER` | `keyring` | where the master key lives: `keyring`, `file` or `env` |
|
|
127
|
+
| `MAILBOX_SERVICE_KEY_FILE` | | the key file, for `file` |
|
|
128
|
+
| `MAILBOX_SERVICE_MASTER_KEY` | | the recovery key, for `env` |
|
|
129
|
+
| `MAILBOX_SERVICE_KEY` | | optional built-in admin key, for containers and tests |
|
|
130
|
+
| `MAILBOX_SERVICE_SYNC_INTERVAL` | `300` | seconds between two polls of every folder. `0` switches the sync off. |
|
|
131
|
+
| `MAILBOX_SERVICE_SYNC_IDLE` | `true` | watch the inbox over IMAP IDLE, with a second connection per account |
|
|
132
|
+
| `MAILBOX_SERVICE_DISCOVERY_ISPDB` | `true` | whether autodiscovery asks Thunderbird's ISPDB (tells Mozilla the domain) |
|
|
133
|
+
| `MAILBOX_SERVICE_DISCOVERY_INTERNAL_HOSTS` | `[]` | JSON list of hosts that may resolve to private addresses, e.g. an internal mail server. Autodiscovery may look them up and accounts may use them. |
|
|
134
|
+
| `MAILBOX_SERVICE_OAUTH_MICROSOFT_CLIENT_ID` | | the Entra app for Microsoft accounts. Without it they cannot be connected. |
|
|
135
|
+
| `MAILBOX_SERVICE_OAUTH_MICROSOFT_CLIENT_SECRET` | | its client secret, or better: |
|
|
136
|
+
| `MAILBOX_SERVICE_OAUTH_MICROSOFT_CLIENT_SECRET_FILE` | | a file holding it |
|
|
137
|
+
| `MAILBOX_SERVICE_OAUTH_MICROSOFT_TENANT` | `common` | who may sign in: `common`, `consumers`, `organizations` or one tenant |
|
|
138
|
+
|
|
139
|
+
## Commands
|
|
140
|
+
|
|
141
|
+
| Command | What it does |
|
|
142
|
+
|---|---|
|
|
143
|
+
| `serve [--host H] [--port P]` | runs the service |
|
|
144
|
+
| `keys init` | creates the keys, prints the recovery key once |
|
|
145
|
+
| `keys import` | stores the master key from a recovery key read from stdin, e.g. on a new machine |
|
|
146
|
+
| `keys generate` | prints a new master key for a key file or a container secret, stores nothing |
|
|
147
|
+
| `users create-admin` | creates a user with every right and prints its token |
|
|
148
|
+
| `backup FILE` | writes an encrypted backup, while the service runs |
|
|
149
|
+
| `backup verify FILE [--recovery-key]` | checks a backup |
|
|
150
|
+
| `restore FILE [--recovery-key]` | replaces the database with a backup. Stop the service first. |
|
|
151
|
+
| `openapi` | prints the OpenAPI document |
|
|
152
|
+
|
|
153
|
+
A backup holds accounts, users, rights, token hashes and the encrypted
|
|
154
|
+
credentials, never mail. It is encrypted as a whole and opens only with
|
|
155
|
+
the master key or the recovery key, which are not in it. `restore` keeps
|
|
156
|
+
the previous database beside the restored one. With `--recovery-key` it
|
|
157
|
+
reads the recovery key from stdin, for a new machine.
|
|
158
|
+
|
|
159
|
+
## Users, rights and tokens
|
|
160
|
+
|
|
161
|
+
Every route under `/v1` needs `Authorization: Bearer <token>`. Only
|
|
162
|
+
`/health` is open. A token belongs to a user. The user's grants decide
|
|
163
|
+
what it may do, per account and per operation: for example read mail,
|
|
164
|
+
write drafts, send, manage accounts. Grants can limit sending to certain
|
|
165
|
+
recipients and to a number of mails per day. Every send is recorded in an
|
|
166
|
+
audit. `GET /v1/me` shows what a token may do.
|
|
167
|
+
|
|
168
|
+
Users, roles and tokens are managed in the UI (Users, Roles) or under
|
|
169
|
+
`/v1/users` and `/v1/roles`. A token is shown once, when it is created.
|
|
170
|
+
Give each script and each assistant its own user with only the rights it
|
|
171
|
+
needs. With neither a user nor `MAILBOX_SERVICE_KEY`, the API answers
|
|
172
|
+
`503 setup_required`.
|
|
173
|
+
|
|
174
|
+
## Container
|
|
175
|
+
|
|
176
|
+
The image `ghcr.io/benethos-hub/benethos-mailbox-service` runs as an
|
|
177
|
+
unprivileged user on a read-only root file system. It takes its settings
|
|
178
|
+
from the environment only and sets `MAILBOX_SERVICE_HOST=0.0.0.0`,
|
|
179
|
+
`MAILBOX_SERVICE_DATA_DIR=/data`, `MAILBOX_SERVICE_KEY_PROVIDER=file` and
|
|
180
|
+
`MAILBOX_SERVICE_KEY_FILE=/run/secrets/master_key`. The database lives in the
|
|
181
|
+
volume at `/data`. The master key is a file mounted at
|
|
182
|
+
`/run/secrets/master_key`. Tags: the version (`0.1.0`), the minor version
|
|
183
|
+
(`0.1`) and `latest`.
|
|
184
|
+
|
|
185
|
+
### With docker run
|
|
186
|
+
|
|
187
|
+
```sh
|
|
188
|
+
IMAGE=ghcr.io/benethos-hub/benethos-mailbox-service:0.1.0
|
|
189
|
+
|
|
190
|
+
# once: a master key file, the keys in the database, the first user
|
|
191
|
+
docker run --rm "$IMAGE" keys generate > master_key
|
|
192
|
+
chmod 400 master_key
|
|
193
|
+
sudo chown 10001 master_key # Linux: the container user (uid 10001) reads it
|
|
194
|
+
docker volume create mailbox-data
|
|
195
|
+
docker run --rm -v mailbox-data:/data -v "$PWD/master_key:/run/secrets/master_key:ro" "$IMAGE" keys init
|
|
196
|
+
docker run --rm -v mailbox-data:/data -v "$PWD/master_key:/run/secrets/master_key:ro" "$IMAGE" users create-admin
|
|
197
|
+
|
|
198
|
+
# the service, on the loopback address of the host only
|
|
199
|
+
docker run -d --name mailbox-service --restart unless-stopped \
|
|
200
|
+
-p 127.0.0.1:8080:8080 --read-only --tmpfs /tmp \
|
|
201
|
+
-v mailbox-data:/data -v "$PWD/master_key:/run/secrets/master_key:ro" \
|
|
202
|
+
"$IMAGE"
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
The file `master_key` holds the recovery key. Whoever has it and a backup
|
|
206
|
+
has the credentials. Keep a copy apart from the host.
|
|
207
|
+
|
|
208
|
+
### With compose
|
|
209
|
+
|
|
210
|
+
The repository's
|
|
211
|
+
[containers/compose.yaml](https://github.com/benethos-hub/mailbox/blob/main/containers/compose.yaml)
|
|
212
|
+
runs the service. With the profile `mcp` it also runs the MCP server over
|
|
213
|
+
HTTP. Both listen on `127.0.0.1` only. From the folder that holds the
|
|
214
|
+
file:
|
|
215
|
+
|
|
216
|
+
```sh
|
|
217
|
+
export MAILBOX_SERVICE_IMAGE=ghcr.io/benethos-hub/benethos-mailbox-service:0.1.0
|
|
218
|
+
|
|
219
|
+
mkdir -p secrets
|
|
220
|
+
docker run --rm "$MAILBOX_SERVICE_IMAGE" keys generate > secrets/master_key
|
|
221
|
+
chmod 400 secrets/master_key
|
|
222
|
+
sudo chown 10001 secrets/master_key # Linux: the container user reads it
|
|
223
|
+
|
|
224
|
+
docker compose run --rm mailbox-service keys init
|
|
225
|
+
docker compose run --rm mailbox-service users create-admin
|
|
226
|
+
docker compose up -d
|
|
227
|
+
curl http://127.0.0.1:8080/health
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Without `MAILBOX_SERVICE_IMAGE`, compose builds the image from a clone of the
|
|
231
|
+
repository. Settings go into the `environment` of the service in the
|
|
232
|
+
compose file.
|
|
233
|
+
|
|
234
|
+
Operation:
|
|
235
|
+
|
|
236
|
+
```sh
|
|
237
|
+
docker compose logs -f mailbox-service
|
|
238
|
+
docker compose pull && docker compose up -d # update
|
|
239
|
+
docker compose exec mailbox-service benethos-mailbox-service backup /data/backup.mbx
|
|
240
|
+
docker compose cp mailbox-service:/data/backup.mbx .
|
|
241
|
+
|
|
242
|
+
# restore, into a stopped service
|
|
243
|
+
docker compose stop mailbox-service
|
|
244
|
+
docker compose cp backup.mbx mailbox-service:/data/backup.mbx
|
|
245
|
+
docker compose run --rm mailbox-service restore /data/backup.mbx
|
|
246
|
+
docker compose up -d
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
Beyond your own machine, put a TLS reverse proxy in front and set
|
|
250
|
+
`MAILBOX_SERVICE_PUBLIC_URL` to the address it serves.
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# benethos-mailbox-service
|
|
2
|
+
|
|
3
|
+
[](https://github.com/benethos-hub/mailbox/actions/workflows/ci.yml)
|
|
4
|
+
[](https://pypi.org/project/benethos-mailbox-service/)
|
|
5
|
+
[](https://github.com/benethos-hub/mailbox/pkgs/container/benethos-mailbox-service)
|
|
6
|
+
[](https://pypi.org/project/benethos-mailbox-service/)
|
|
7
|
+
[](https://github.com/benethos-hub/mailbox/blob/main/LICENSE)
|
|
8
|
+
|
|
9
|
+
> **Pre-alpha, version 0.1.0.** Not ready for production use: the API,
|
|
10
|
+
> the stored data and the configuration may change without notice.
|
|
11
|
+
|
|
12
|
+
The Mailbox Service: one REST API (OpenAPI 3.1) for several mail
|
|
13
|
+
providers and accounts, with a configuration UI in the browser. It runs
|
|
14
|
+
permanently, holds the connections to the accounts, keeps their
|
|
15
|
+
credentials encrypted and syncs in the background. Scripts, apps and the
|
|
16
|
+
MCP server [`benethos-mailbox-mcp`](https://github.com/benethos-hub/mailbox/tree/main/packages/mailbox-mcp)
|
|
17
|
+
reach mail only through it, each with a token of its own.
|
|
18
|
+
|
|
19
|
+
What the project is for: [the repository's README](https://github.com/benethos-hub/mailbox#readme).
|
|
20
|
+
|
|
21
|
+
## Install
|
|
22
|
+
|
|
23
|
+
From PyPI, with [uv](https://docs.astral.sh/uv/) or pip:
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
uv tool install benethos-mailbox-service # or: pipx install benethos-mailbox-service
|
|
27
|
+
benethos-mailbox-service --version
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`uvx benethos-mailbox-service ...` runs it without installing. In a clone of
|
|
31
|
+
the repository, every command below also works as
|
|
32
|
+
`uv run benethos-mailbox-service ...`.
|
|
33
|
+
|
|
34
|
+
The container image is `ghcr.io/benethos-hub/benethos-mailbox-service`. See
|
|
35
|
+
[Container](#container).
|
|
36
|
+
|
|
37
|
+
## First start
|
|
38
|
+
|
|
39
|
+
```sh
|
|
40
|
+
benethos-mailbox-service keys init # once: the keys; prints the recovery key
|
|
41
|
+
benethos-mailbox-service users create-admin # once: a user with every right; prints its token
|
|
42
|
+
benethos-mailbox-service serve
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
- `keys init` creates the master key in the operating system's credential
|
|
46
|
+
store and the data key in the database. It prints a **recovery key**
|
|
47
|
+
once. Keep it apart from the machine and its backups. Without it, a
|
|
48
|
+
database cannot be opened on another machine.
|
|
49
|
+
- `users create-admin` prints an API token once. Use it to sign in to the
|
|
50
|
+
UI, and send it as `Authorization: Bearer <token>` to the API.
|
|
51
|
+
- `serve` listens on `http://127.0.0.1:8080`:
|
|
52
|
+
- `/ui`: the configuration UI (sign in with the token)
|
|
53
|
+
- `/docs`: the interactive API documentation
|
|
54
|
+
- `/health`: open, for health checks
|
|
55
|
+
|
|
56
|
+
Then connect accounts in the UI (Accounts, Connect an account) or with
|
|
57
|
+
`POST /v1/accounts`. An IMAP account needs its address and an app
|
|
58
|
+
password. The service looks up the servers from the address. Microsoft
|
|
59
|
+
accounts sign in with OAuth and need an app registration first:
|
|
60
|
+
[docs/microsoft.md](https://github.com/benethos-hub/mailbox/blob/main/docs/microsoft.md).
|
|
61
|
+
|
|
62
|
+
## Where things live
|
|
63
|
+
|
|
64
|
+
The service works from the folder it is started in:
|
|
65
|
+
|
|
66
|
+
| What | Where |
|
|
67
|
+
|---|---|
|
|
68
|
+
| settings | the environment, or `config/benethos-mailbox-service/.env` (the environment wins) |
|
|
69
|
+
| the database | `data/benethos-mailbox-service/mailbox.db`, readable by its owner only |
|
|
70
|
+
| the master key | the OS credential store (keyring), or a file or variable (see `MAILBOX_SERVICE_KEY_PROVIDER`) |
|
|
71
|
+
|
|
72
|
+
A template for the settings file with every option:
|
|
73
|
+
[config/benethos-mailbox-service/.env.example](https://github.com/benethos-hub/mailbox/blob/main/config/benethos-mailbox-service/.env.example).
|
|
74
|
+
|
|
75
|
+
## Settings
|
|
76
|
+
|
|
77
|
+
| Setting | Default | Meaning |
|
|
78
|
+
|---|---|---|
|
|
79
|
+
| `MAILBOX_SERVICE_HOST`, `MAILBOX_SERVICE_PORT` | `127.0.0.1`, `8080` | where the service listens (`serve --host/--port` win) |
|
|
80
|
+
| `MAILBOX_SERVICE_PUBLIC_URL` | from each request | the address people reach the service at, e.g. behind a proxy. The OAuth redirect address is built from it. |
|
|
81
|
+
| `MAILBOX_SERVICE_FORWARDED_ALLOW_IPS` | `127.0.0.1` | behind a reverse proxy: its address, whose `X-Forwarded-*` headers give the client address, scheme and host |
|
|
82
|
+
| `MAILBOX_SERVICE_LOG_LEVEL` | `INFO` | |
|
|
83
|
+
| `MAILBOX_SERVICE_DATA_DIR` | `data/benethos-mailbox-service` | where the database lives |
|
|
84
|
+
| `MAILBOX_SERVICE_STORAGE` | `sqlite` | or `memory`, which keeps nothing |
|
|
85
|
+
| `MAILBOX_SERVICE_KEY_PROVIDER` | `keyring` | where the master key lives: `keyring`, `file` or `env` |
|
|
86
|
+
| `MAILBOX_SERVICE_KEY_FILE` | | the key file, for `file` |
|
|
87
|
+
| `MAILBOX_SERVICE_MASTER_KEY` | | the recovery key, for `env` |
|
|
88
|
+
| `MAILBOX_SERVICE_KEY` | | optional built-in admin key, for containers and tests |
|
|
89
|
+
| `MAILBOX_SERVICE_SYNC_INTERVAL` | `300` | seconds between two polls of every folder. `0` switches the sync off. |
|
|
90
|
+
| `MAILBOX_SERVICE_SYNC_IDLE` | `true` | watch the inbox over IMAP IDLE, with a second connection per account |
|
|
91
|
+
| `MAILBOX_SERVICE_DISCOVERY_ISPDB` | `true` | whether autodiscovery asks Thunderbird's ISPDB (tells Mozilla the domain) |
|
|
92
|
+
| `MAILBOX_SERVICE_DISCOVERY_INTERNAL_HOSTS` | `[]` | JSON list of hosts that may resolve to private addresses, e.g. an internal mail server. Autodiscovery may look them up and accounts may use them. |
|
|
93
|
+
| `MAILBOX_SERVICE_OAUTH_MICROSOFT_CLIENT_ID` | | the Entra app for Microsoft accounts. Without it they cannot be connected. |
|
|
94
|
+
| `MAILBOX_SERVICE_OAUTH_MICROSOFT_CLIENT_SECRET` | | its client secret, or better: |
|
|
95
|
+
| `MAILBOX_SERVICE_OAUTH_MICROSOFT_CLIENT_SECRET_FILE` | | a file holding it |
|
|
96
|
+
| `MAILBOX_SERVICE_OAUTH_MICROSOFT_TENANT` | `common` | who may sign in: `common`, `consumers`, `organizations` or one tenant |
|
|
97
|
+
|
|
98
|
+
## Commands
|
|
99
|
+
|
|
100
|
+
| Command | What it does |
|
|
101
|
+
|---|---|
|
|
102
|
+
| `serve [--host H] [--port P]` | runs the service |
|
|
103
|
+
| `keys init` | creates the keys, prints the recovery key once |
|
|
104
|
+
| `keys import` | stores the master key from a recovery key read from stdin, e.g. on a new machine |
|
|
105
|
+
| `keys generate` | prints a new master key for a key file or a container secret, stores nothing |
|
|
106
|
+
| `users create-admin` | creates a user with every right and prints its token |
|
|
107
|
+
| `backup FILE` | writes an encrypted backup, while the service runs |
|
|
108
|
+
| `backup verify FILE [--recovery-key]` | checks a backup |
|
|
109
|
+
| `restore FILE [--recovery-key]` | replaces the database with a backup. Stop the service first. |
|
|
110
|
+
| `openapi` | prints the OpenAPI document |
|
|
111
|
+
|
|
112
|
+
A backup holds accounts, users, rights, token hashes and the encrypted
|
|
113
|
+
credentials, never mail. It is encrypted as a whole and opens only with
|
|
114
|
+
the master key or the recovery key, which are not in it. `restore` keeps
|
|
115
|
+
the previous database beside the restored one. With `--recovery-key` it
|
|
116
|
+
reads the recovery key from stdin, for a new machine.
|
|
117
|
+
|
|
118
|
+
## Users, rights and tokens
|
|
119
|
+
|
|
120
|
+
Every route under `/v1` needs `Authorization: Bearer <token>`. Only
|
|
121
|
+
`/health` is open. A token belongs to a user. The user's grants decide
|
|
122
|
+
what it may do, per account and per operation: for example read mail,
|
|
123
|
+
write drafts, send, manage accounts. Grants can limit sending to certain
|
|
124
|
+
recipients and to a number of mails per day. Every send is recorded in an
|
|
125
|
+
audit. `GET /v1/me` shows what a token may do.
|
|
126
|
+
|
|
127
|
+
Users, roles and tokens are managed in the UI (Users, Roles) or under
|
|
128
|
+
`/v1/users` and `/v1/roles`. A token is shown once, when it is created.
|
|
129
|
+
Give each script and each assistant its own user with only the rights it
|
|
130
|
+
needs. With neither a user nor `MAILBOX_SERVICE_KEY`, the API answers
|
|
131
|
+
`503 setup_required`.
|
|
132
|
+
|
|
133
|
+
## Container
|
|
134
|
+
|
|
135
|
+
The image `ghcr.io/benethos-hub/benethos-mailbox-service` runs as an
|
|
136
|
+
unprivileged user on a read-only root file system. It takes its settings
|
|
137
|
+
from the environment only and sets `MAILBOX_SERVICE_HOST=0.0.0.0`,
|
|
138
|
+
`MAILBOX_SERVICE_DATA_DIR=/data`, `MAILBOX_SERVICE_KEY_PROVIDER=file` and
|
|
139
|
+
`MAILBOX_SERVICE_KEY_FILE=/run/secrets/master_key`. The database lives in the
|
|
140
|
+
volume at `/data`. The master key is a file mounted at
|
|
141
|
+
`/run/secrets/master_key`. Tags: the version (`0.1.0`), the minor version
|
|
142
|
+
(`0.1`) and `latest`.
|
|
143
|
+
|
|
144
|
+
### With docker run
|
|
145
|
+
|
|
146
|
+
```sh
|
|
147
|
+
IMAGE=ghcr.io/benethos-hub/benethos-mailbox-service:0.1.0
|
|
148
|
+
|
|
149
|
+
# once: a master key file, the keys in the database, the first user
|
|
150
|
+
docker run --rm "$IMAGE" keys generate > master_key
|
|
151
|
+
chmod 400 master_key
|
|
152
|
+
sudo chown 10001 master_key # Linux: the container user (uid 10001) reads it
|
|
153
|
+
docker volume create mailbox-data
|
|
154
|
+
docker run --rm -v mailbox-data:/data -v "$PWD/master_key:/run/secrets/master_key:ro" "$IMAGE" keys init
|
|
155
|
+
docker run --rm -v mailbox-data:/data -v "$PWD/master_key:/run/secrets/master_key:ro" "$IMAGE" users create-admin
|
|
156
|
+
|
|
157
|
+
# the service, on the loopback address of the host only
|
|
158
|
+
docker run -d --name mailbox-service --restart unless-stopped \
|
|
159
|
+
-p 127.0.0.1:8080:8080 --read-only --tmpfs /tmp \
|
|
160
|
+
-v mailbox-data:/data -v "$PWD/master_key:/run/secrets/master_key:ro" \
|
|
161
|
+
"$IMAGE"
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
The file `master_key` holds the recovery key. Whoever has it and a backup
|
|
165
|
+
has the credentials. Keep a copy apart from the host.
|
|
166
|
+
|
|
167
|
+
### With compose
|
|
168
|
+
|
|
169
|
+
The repository's
|
|
170
|
+
[containers/compose.yaml](https://github.com/benethos-hub/mailbox/blob/main/containers/compose.yaml)
|
|
171
|
+
runs the service. With the profile `mcp` it also runs the MCP server over
|
|
172
|
+
HTTP. Both listen on `127.0.0.1` only. From the folder that holds the
|
|
173
|
+
file:
|
|
174
|
+
|
|
175
|
+
```sh
|
|
176
|
+
export MAILBOX_SERVICE_IMAGE=ghcr.io/benethos-hub/benethos-mailbox-service:0.1.0
|
|
177
|
+
|
|
178
|
+
mkdir -p secrets
|
|
179
|
+
docker run --rm "$MAILBOX_SERVICE_IMAGE" keys generate > secrets/master_key
|
|
180
|
+
chmod 400 secrets/master_key
|
|
181
|
+
sudo chown 10001 secrets/master_key # Linux: the container user reads it
|
|
182
|
+
|
|
183
|
+
docker compose run --rm mailbox-service keys init
|
|
184
|
+
docker compose run --rm mailbox-service users create-admin
|
|
185
|
+
docker compose up -d
|
|
186
|
+
curl http://127.0.0.1:8080/health
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Without `MAILBOX_SERVICE_IMAGE`, compose builds the image from a clone of the
|
|
190
|
+
repository. Settings go into the `environment` of the service in the
|
|
191
|
+
compose file.
|
|
192
|
+
|
|
193
|
+
Operation:
|
|
194
|
+
|
|
195
|
+
```sh
|
|
196
|
+
docker compose logs -f mailbox-service
|
|
197
|
+
docker compose pull && docker compose up -d # update
|
|
198
|
+
docker compose exec mailbox-service benethos-mailbox-service backup /data/backup.mbx
|
|
199
|
+
docker compose cp mailbox-service:/data/backup.mbx .
|
|
200
|
+
|
|
201
|
+
# restore, into a stopped service
|
|
202
|
+
docker compose stop mailbox-service
|
|
203
|
+
docker compose cp backup.mbx mailbox-service:/data/backup.mbx
|
|
204
|
+
docker compose run --rm mailbox-service restore /data/backup.mbx
|
|
205
|
+
docker compose up -d
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Beyond your own machine, put a TLS reverse proxy in front and set
|
|
209
|
+
`MAILBOX_SERVICE_PUBLIC_URL` to the address it serves.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "benethos-mailbox-service"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Self-hosted mail service: one REST API and a web UI for IMAP and Microsoft 365 / Outlook.com accounts, with users, rights and encrypted credentials."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
authors = [{ name = "Benedikt Oswald" }]
|
|
14
|
+
keywords = [
|
|
15
|
+
"email",
|
|
16
|
+
"mail",
|
|
17
|
+
"imap",
|
|
18
|
+
"smtp",
|
|
19
|
+
"microsoft-graph",
|
|
20
|
+
"outlook",
|
|
21
|
+
"microsoft-365",
|
|
22
|
+
"rest-api",
|
|
23
|
+
"openapi",
|
|
24
|
+
"fastapi",
|
|
25
|
+
"oauth2",
|
|
26
|
+
"multi-account",
|
|
27
|
+
"self-hosted",
|
|
28
|
+
"email-automation",
|
|
29
|
+
]
|
|
30
|
+
classifiers = [
|
|
31
|
+
"Development Status :: 2 - Pre-Alpha",
|
|
32
|
+
"Environment :: Web Environment",
|
|
33
|
+
"Framework :: FastAPI",
|
|
34
|
+
"Intended Audience :: Developers",
|
|
35
|
+
"Operating System :: OS Independent",
|
|
36
|
+
"Programming Language :: Python :: 3",
|
|
37
|
+
"Programming Language :: Python :: 3.11",
|
|
38
|
+
"Programming Language :: Python :: 3.12",
|
|
39
|
+
"Programming Language :: Python :: 3.13",
|
|
40
|
+
"Programming Language :: Python :: 3.14",
|
|
41
|
+
"Topic :: Communications :: Email",
|
|
42
|
+
]
|
|
43
|
+
dependencies = [
|
|
44
|
+
"fastapi>=0.120",
|
|
45
|
+
"uvicorn>=0.38",
|
|
46
|
+
# The configuration UI: server-rendered pages (web/pages/) and their
|
|
47
|
+
# forms.
|
|
48
|
+
"jinja2>=3.1",
|
|
49
|
+
"python-multipart>=0.0.20",
|
|
50
|
+
"pydantic>=2.11",
|
|
51
|
+
"pydantic-settings>=2.10",
|
|
52
|
+
# Outbound HTTP: autodiscovery, later the Gmail and Microsoft Graph
|
|
53
|
+
# adapters.
|
|
54
|
+
"httpx>=0.28",
|
|
55
|
+
# AES-256-GCM for stored credentials.
|
|
56
|
+
"cryptography>=44",
|
|
57
|
+
# The OS credential store that holds the master key on a host.
|
|
58
|
+
"keyring>=25",
|
|
59
|
+
# IMAP: search builder, message parsing, folder name decoding.
|
|
60
|
+
"imap-tools>=1.10",
|
|
61
|
+
# Worker threads for the synchronous IMAP library.
|
|
62
|
+
"anyio>=4",
|
|
63
|
+
# Autodiscovery: MX and SRV lookups.
|
|
64
|
+
"dnspython>=2.6",
|
|
65
|
+
# Autodiscovery: autoconfig XML without entity expansion.
|
|
66
|
+
"defusedxml>=0.7",
|
|
67
|
+
# Autodiscovery: where a domain ends. Ships its own copy of the list.
|
|
68
|
+
"publicsuffixlist>=1.0",
|
|
69
|
+
"imapclient>=4.1.0",
|
|
70
|
+
]
|
|
71
|
+
|
|
72
|
+
[project.urls]
|
|
73
|
+
Homepage = "https://github.com/benethos-hub/mailbox/tree/main/packages/mailbox-service#readme"
|
|
74
|
+
Repository = "https://github.com/benethos-hub/mailbox"
|
|
75
|
+
Issues = "https://github.com/benethos-hub/mailbox/issues"
|
|
76
|
+
Changelog = "https://github.com/benethos-hub/mailbox/blob/main/CHANGELOG.md"
|
|
77
|
+
|
|
78
|
+
[project.scripts]
|
|
79
|
+
benethos-mailbox-service = "benethos_mailbox_service.__main__:main"
|
|
80
|
+
|
|
81
|
+
[tool.hatch.build.targets.wheel]
|
|
82
|
+
packages = ["src/benethos_mailbox_service"]
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""Unified REST API for several mail providers and accounts."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
6
|
+
|
|
7
|
+
try:
|
|
8
|
+
__version__ = version("benethos-mailbox-service")
|
|
9
|
+
except PackageNotFoundError: # pragma: no cover (running from a bare tree)
|
|
10
|
+
__version__ = "0.0.0"
|
|
11
|
+
|
|
12
|
+
__all__ = ["__version__"]
|