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.
Files changed (244) hide show
  1. benethos_mailbox_service-0.1.0/.gitignore +56 -0
  2. benethos_mailbox_service-0.1.0/LICENSE +21 -0
  3. benethos_mailbox_service-0.1.0/PKG-INFO +250 -0
  4. benethos_mailbox_service-0.1.0/README.md +209 -0
  5. benethos_mailbox_service-0.1.0/pyproject.toml +82 -0
  6. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/__init__.py +12 -0
  7. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/__main__.py +256 -0
  8. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/common/__init__.py +6 -0
  9. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/common/clock.py +10 -0
  10. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/common/ids.py +11 -0
  11. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/common/opaque.py +28 -0
  12. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/config.py +88 -0
  13. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/__init__.py +7 -0
  14. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/discovery/__init__.py +51 -0
  15. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/discovery/autoconfig.py +156 -0
  16. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/discovery/base.py +37 -0
  17. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/discovery/dns.py +41 -0
  18. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/discovery/isp.py +43 -0
  19. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/discovery/ispdb.py +32 -0
  20. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/discovery/mx.py +54 -0
  21. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/discovery/placeholders.py +23 -0
  22. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/discovery/presets.json +263 -0
  23. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/discovery/presets.py +101 -0
  24. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/discovery/suffix.py +24 -0
  25. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/files.py +21 -0
  26. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/http/__init__.py +29 -0
  27. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/http/api.py +91 -0
  28. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/http/base.py +52 -0
  29. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/http/safe.py +150 -0
  30. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/mail/__init__.py +6 -0
  31. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/mail/compose.py +250 -0
  32. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/mail/convert.py +78 -0
  33. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/mail/fields.py +35 -0
  34. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/mail/parse.py +123 -0
  35. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/mail/text.py +80 -0
  36. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/models/__init__.py +93 -0
  37. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/models/accounts.py +45 -0
  38. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/models/audit.py +37 -0
  39. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/models/batch.py +51 -0
  40. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/models/discovery.py +99 -0
  41. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/models/folders.py +66 -0
  42. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/models/messages.py +163 -0
  43. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/models/paging.py +33 -0
  44. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/models/sending.py +78 -0
  45. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/models/users.py +63 -0
  46. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/providers/__init__.py +178 -0
  47. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/providers/base.py +178 -0
  48. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/providers/guard.py +129 -0
  49. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/providers/imap/__init__.py +7 -0
  50. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/providers/imap/mappers.py +290 -0
  51. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/providers/imap/provider.py +790 -0
  52. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/providers/memory/__init__.py +7 -0
  53. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/providers/memory/provider.py +298 -0
  54. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/providers/microsoft/__init__.py +9 -0
  55. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/providers/microsoft/mappers.py +217 -0
  56. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/providers/microsoft/provider.py +555 -0
  57. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/providers/microsoft/signin.py +41 -0
  58. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/providers/protocols/__init__.py +8 -0
  59. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/providers/protocols/imap.py +583 -0
  60. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/providers/protocols/oauth.py +261 -0
  61. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/providers/protocols/smtp.py +168 -0
  62. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/providers/protocols/transport.py +28 -0
  63. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/providers/ratelimit.py +57 -0
  64. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/providers/rules.py +116 -0
  65. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/providers/sender.py +76 -0
  66. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/secrets/__init__.py +28 -0
  67. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/secrets/backup.py +121 -0
  68. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/secrets/cipher.py +43 -0
  69. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/secrets/keys.py +132 -0
  70. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/secrets/vault.py +170 -0
  71. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/storage/__init__.py +145 -0
  72. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/storage/accounts.py +72 -0
  73. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/storage/credentials.py +73 -0
  74. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/storage/idempotency.py +51 -0
  75. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/storage/index.py +141 -0
  76. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/storage/sends.py +61 -0
  77. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/storage/sqlite/__init__.py +27 -0
  78. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/storage/sqlite/accounts.py +80 -0
  79. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/storage/sqlite/credentials.py +76 -0
  80. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/storage/sqlite/database.py +325 -0
  81. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/storage/sqlite/idempotency.py +48 -0
  82. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/storage/sqlite/index.py +142 -0
  83. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/storage/sqlite/rows.py +39 -0
  84. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/storage/sqlite/sends.py +79 -0
  85. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/storage/sqlite/users.py +127 -0
  86. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/storage/table.py +77 -0
  87. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/data/storage/users.py +85 -0
  88. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/domain/__init__.py +7 -0
  89. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/domain/access.py +233 -0
  90. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/domain/accounts.py +267 -0
  91. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/domain/adapters.py +156 -0
  92. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/domain/auth.py +148 -0
  93. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/domain/calls.py +236 -0
  94. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/domain/discovery.py +386 -0
  95. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/domain/idempotency.py +88 -0
  96. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/domain/locks.py +29 -0
  97. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/domain/mailbox.py +405 -0
  98. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/domain/merge.py +94 -0
  99. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/domain/oauth.py +190 -0
  100. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/domain/outgoing.py +395 -0
  101. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/domain/paging.py +17 -0
  102. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/domain/permissions.py +141 -0
  103. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/domain/replies.py +98 -0
  104. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/domain/sending.py +162 -0
  105. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/domain/sync.py +218 -0
  106. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/domain/throttle.py +105 -0
  107. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/domain/users.py +306 -0
  108. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/domain/worker.py +126 -0
  109. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/errors.py +128 -0
  110. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/main.py +234 -0
  111. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/py.typed +0 -0
  112. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/__init__.py +53 -0
  113. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/api/__init__.py +56 -0
  114. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/api/deps.py +101 -0
  115. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/api/errors.py +68 -0
  116. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/api/routes/__init__.py +1 -0
  117. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/api/routes/accounts.py +62 -0
  118. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/api/routes/discovery.py +27 -0
  119. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/api/routes/health.py +12 -0
  120. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/api/routes/mailbox.py +302 -0
  121. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/api/routes/messages.py +37 -0
  122. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/api/routes/oauth.py +38 -0
  123. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/api/routes/users.py +120 -0
  124. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/api/schemas.py +177 -0
  125. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/errors.py +43 -0
  126. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/__init__.py +137 -0
  127. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/deps.py +50 -0
  128. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/effective.py +54 -0
  129. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/errors.py +23 -0
  130. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/forms.py +47 -0
  131. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/grants.py +137 -0
  132. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/mailform.py +210 -0
  133. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/rights.py +21 -0
  134. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/routes/__init__.py +2 -0
  135. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/routes/accounts.py +206 -0
  136. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/routes/compose.py +66 -0
  137. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/routes/drafts.py +143 -0
  138. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/routes/folders.py +95 -0
  139. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/routes/home.py +23 -0
  140. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/routes/login.py +92 -0
  141. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/routes/mail.py +212 -0
  142. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/routes/messages.py +114 -0
  143. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/routes/oauth.py +84 -0
  144. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/routes/sends.py +64 -0
  145. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/routes/users.py +264 -0
  146. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/session.py +119 -0
  147. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/static/css/app.css +400 -0
  148. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/static/js/app.js +32 -0
  149. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/static/vendor/htmx/README.md +2 -0
  150. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/static/vendor/htmx/htmx.min.js +1 -0
  151. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/bare.html +22 -0
  152. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/base.html +34 -0
  153. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/components/connection.html +50 -0
  154. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/components/grants.html +75 -0
  155. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/components/ui.html +72 -0
  156. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/pages/account.html +68 -0
  157. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/pages/account_mail.html +107 -0
  158. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/pages/account_new.html +126 -0
  159. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/pages/accounts.html +37 -0
  160. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/pages/compose.html +102 -0
  161. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/pages/drafts.html +12 -0
  162. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/pages/error.html +7 -0
  163. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/pages/home.html +46 -0
  164. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/pages/login.html +18 -0
  165. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/pages/mail.html +27 -0
  166. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/pages/message.html +86 -0
  167. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/pages/oauth_bounce.html +11 -0
  168. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/pages/role.html +37 -0
  169. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/pages/roles.html +51 -0
  170. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/pages/sends.html +64 -0
  171. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/pages/user.html +141 -0
  172. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/pages/user_new.html +28 -0
  173. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/pages/users.html +39 -0
  174. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/partials/account_status.html +5 -0
  175. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/partials/flash.html +5 -0
  176. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/partials/mail_search.html +26 -0
  177. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/partials/message_list.html +42 -0
  178. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates/partials/sidebar.html +24 -0
  179. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/pages/templates.py +143 -0
  180. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/responses.py +18 -0
  181. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/search.py +33 -0
  182. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/services.py +67 -0
  183. benethos_mailbox_service-0.1.0/src/benethos_mailbox_service/web/urls.py +28 -0
  184. benethos_mailbox_service-0.1.0/tests/conftest.py +173 -0
  185. benethos_mailbox_service-0.1.0/tests/graph_fake.py +328 -0
  186. benethos_mailbox_service-0.1.0/tests/imap_fake.py +423 -0
  187. benethos_mailbox_service-0.1.0/tests/provider_ops.py +26 -0
  188. benethos_mailbox_service-0.1.0/tests/smtp_fake.py +77 -0
  189. benethos_mailbox_service-0.1.0/tests/test_access.py +137 -0
  190. benethos_mailbox_service-0.1.0/tests/test_account_hosts.py +123 -0
  191. benethos_mailbox_service-0.1.0/tests/test_account_status.py +62 -0
  192. benethos_mailbox_service-0.1.0/tests/test_accounts.py +90 -0
  193. benethos_mailbox_service-0.1.0/tests/test_across_accounts.py +195 -0
  194. benethos_mailbox_service-0.1.0/tests/test_architecture.py +194 -0
  195. benethos_mailbox_service-0.1.0/tests/test_auth.py +201 -0
  196. benethos_mailbox_service-0.1.0/tests/test_backup.py +264 -0
  197. benethos_mailbox_service-0.1.0/tests/test_batch.py +167 -0
  198. benethos_mailbox_service-0.1.0/tests/test_cli.py +77 -0
  199. benethos_mailbox_service-0.1.0/tests/test_delete.py +98 -0
  200. benethos_mailbox_service-0.1.0/tests/test_discovery.py +590 -0
  201. benethos_mailbox_service-0.1.0/tests/test_discovery_parts.py +469 -0
  202. benethos_mailbox_service-0.1.0/tests/test_discovery_sources.py +279 -0
  203. benethos_mailbox_service-0.1.0/tests/test_draft_reference.py +64 -0
  204. benethos_mailbox_service-0.1.0/tests/test_drafts.py +458 -0
  205. benethos_mailbox_service-0.1.0/tests/test_folders.py +212 -0
  206. benethos_mailbox_service-0.1.0/tests/test_health_and_auth.py +46 -0
  207. benethos_mailbox_service-0.1.0/tests/test_html_mail.py +99 -0
  208. benethos_mailbox_service-0.1.0/tests/test_idempotency.py +245 -0
  209. benethos_mailbox_service-0.1.0/tests/test_ids.py +15 -0
  210. benethos_mailbox_service-0.1.0/tests/test_imap.py +471 -0
  211. benethos_mailbox_service-0.1.0/tests/test_imap_encodings.py +148 -0
  212. benethos_mailbox_service-0.1.0/tests/test_imap_probe.py +68 -0
  213. benethos_mailbox_service-0.1.0/tests/test_imap_sync.py +183 -0
  214. benethos_mailbox_service-0.1.0/tests/test_index_storage.py +156 -0
  215. benethos_mailbox_service-0.1.0/tests/test_mailbox.py +79 -0
  216. benethos_mailbox_service-0.1.0/tests/test_microsoft.py +472 -0
  217. benethos_mailbox_service-0.1.0/tests/test_move.py +120 -0
  218. benethos_mailbox_service-0.1.0/tests/test_oauth.py +507 -0
  219. benethos_mailbox_service-0.1.0/tests/test_openapi.py +67 -0
  220. benethos_mailbox_service-0.1.0/tests/test_packaging.py +114 -0
  221. benethos_mailbox_service-0.1.0/tests/test_permissions.py +77 -0
  222. benethos_mailbox_service-0.1.0/tests/test_ratelimit.py +56 -0
  223. benethos_mailbox_service-0.1.0/tests/test_reply.py +389 -0
  224. benethos_mailbox_service-0.1.0/tests/test_search.py +132 -0
  225. benethos_mailbox_service-0.1.0/tests/test_secrets.py +381 -0
  226. benethos_mailbox_service-0.1.0/tests/test_send.py +254 -0
  227. benethos_mailbox_service-0.1.0/tests/test_send_constraints.py +452 -0
  228. benethos_mailbox_service-0.1.0/tests/test_smtp.py +280 -0
  229. benethos_mailbox_service-0.1.0/tests/test_sqlite.py +210 -0
  230. benethos_mailbox_service-0.1.0/tests/test_storage.py +181 -0
  231. benethos_mailbox_service-0.1.0/tests/test_sync.py +371 -0
  232. benethos_mailbox_service-0.1.0/tests/test_throttle.py +190 -0
  233. benethos_mailbox_service-0.1.0/tests/test_ui.py +270 -0
  234. benethos_mailbox_service-0.1.0/tests/test_ui_accounts.py +187 -0
  235. benethos_mailbox_service-0.1.0/tests/test_ui_mail.py +135 -0
  236. benethos_mailbox_service-0.1.0/tests/test_ui_oauth.py +229 -0
  237. benethos_mailbox_service-0.1.0/tests/test_ui_sends.py +84 -0
  238. benethos_mailbox_service-0.1.0/tests/test_ui_users.py +409 -0
  239. benethos_mailbox_service-0.1.0/tests/test_ui_write.py +379 -0
  240. benethos_mailbox_service-0.1.0/tests/test_update.py +160 -0
  241. benethos_mailbox_service-0.1.0/tests/test_users.py +305 -0
  242. benethos_mailbox_service-0.1.0/tests/test_verify.py +135 -0
  243. benethos_mailbox_service-0.1.0/tests/test_worker.py +183 -0
  244. 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
+ [![CI](https://github.com/benethos-hub/mailbox/actions/workflows/ci.yml/badge.svg)](https://github.com/benethos-hub/mailbox/actions/workflows/ci.yml)
45
+ [![PyPI](https://img.shields.io/pypi/v/benethos-mailbox-service?label=PyPI)](https://pypi.org/project/benethos-mailbox-service/)
46
+ [![Container](https://img.shields.io/badge/ghcr.io-mailbox--api-2496ED?logo=docker&logoColor=white)](https://github.com/benethos-hub/mailbox/pkgs/container/benethos-mailbox-service)
47
+ [![Python](https://img.shields.io/pypi/pyversions/benethos-mailbox-service)](https://pypi.org/project/benethos-mailbox-service/)
48
+ [![License](https://img.shields.io/badge/license-MIT-blue)](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
+ [![CI](https://github.com/benethos-hub/mailbox/actions/workflows/ci.yml/badge.svg)](https://github.com/benethos-hub/mailbox/actions/workflows/ci.yml)
4
+ [![PyPI](https://img.shields.io/pypi/v/benethos-mailbox-service?label=PyPI)](https://pypi.org/project/benethos-mailbox-service/)
5
+ [![Container](https://img.shields.io/badge/ghcr.io-mailbox--api-2496ED?logo=docker&logoColor=white)](https://github.com/benethos-hub/mailbox/pkgs/container/benethos-mailbox-service)
6
+ [![Python](https://img.shields.io/pypi/pyversions/benethos-mailbox-service)](https://pypi.org/project/benethos-mailbox-service/)
7
+ [![License](https://img.shields.io/badge/license-MIT-blue)](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__"]