agentmail-clone-v1 0.1.0

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 (227) hide show
  1. package/.env.example +20 -0
  2. package/.github/workflows/docs-deploy.yml +37 -0
  3. package/.github/workflows/landing-preview.yml +43 -0
  4. package/.github/workflows/openapi-lint.yml +31 -0
  5. package/.github/workflows/sdk-generate-check.yml +66 -0
  6. package/.github/workflows/sdk-release.yml +62 -0
  7. package/CHANGELOG.md +10 -0
  8. package/README.md +208 -0
  9. package/RELEASING.md +43 -0
  10. package/docs/api-reference/api-keys.mdx +11 -0
  11. package/docs/api-reference/domains.mdx +13 -0
  12. package/docs/api-reference/emails.mdx +26 -0
  13. package/docs/api-reference/inboxes.mdx +13 -0
  14. package/docs/api-reference/metrics.mdx +10 -0
  15. package/docs/authentication.mdx +25 -0
  16. package/docs/docs.json +35 -0
  17. package/docs/errors.mdx +34 -0
  18. package/docs/favicon.svg +5 -0
  19. package/docs/idempotency.mdx +18 -0
  20. package/docs/index.mdx +24 -0
  21. package/docs/quickstart.mdx +134 -0
  22. package/landing/DEPLOYING.md +33 -0
  23. package/landing/favicon.svg +5 -0
  24. package/landing/index.html +129 -0
  25. package/landing/main.js +45 -0
  26. package/landing/privacy.html +29 -0
  27. package/landing/styles.css +356 -0
  28. package/landing/terms.html +29 -0
  29. package/netlify.toml +15 -0
  30. package/openapi/openapi.yaml +1016 -0
  31. package/package.json +34 -0
  32. package/render.yaml +48 -0
  33. package/scripts/generate-sdk-py.sh +16 -0
  34. package/scripts/generate-sdk-ts.sh +16 -0
  35. package/scripts/migrate.js +66 -0
  36. package/scripts/validate-docs.js +56 -0
  37. package/scripts/validate-landing.js +39 -0
  38. package/sdks/python/README.md +40 -0
  39. package/sdks/python/emailagent_sdk/__init__.py +157 -0
  40. package/sdks/python/generated/.openapi-generator/FILES +101 -0
  41. package/sdks/python/generated/.openapi-generator/VERSION +1 -0
  42. package/sdks/python/generated/.openapi-generator-ignore +23 -0
  43. package/sdks/python/generated/emailagent_sdk_generated/__init__.py +105 -0
  44. package/sdks/python/generated/emailagent_sdk_generated/api/__init__.py +9 -0
  45. package/sdks/python/generated/emailagent_sdk_generated/api/api_keys_api.py +1162 -0
  46. package/sdks/python/generated/emailagent_sdk_generated/api/domains_api.py +1168 -0
  47. package/sdks/python/generated/emailagent_sdk_generated/api/emails_api.py +1232 -0
  48. package/sdks/python/generated/emailagent_sdk_generated/api/inboxes_api.py +1191 -0
  49. package/sdks/python/generated/emailagent_sdk_generated/api/metrics_api.py +285 -0
  50. package/sdks/python/generated/emailagent_sdk_generated/api_client.py +801 -0
  51. package/sdks/python/generated/emailagent_sdk_generated/api_response.py +21 -0
  52. package/sdks/python/generated/emailagent_sdk_generated/configuration.py +586 -0
  53. package/sdks/python/generated/emailagent_sdk_generated/docs/APIKeysApi.md +334 -0
  54. package/sdks/python/generated/emailagent_sdk_generated/docs/ApiKeyCreated.md +35 -0
  55. package/sdks/python/generated/emailagent_sdk_generated/docs/ApiKeyCreatedResponse.md +29 -0
  56. package/sdks/python/generated/emailagent_sdk_generated/docs/ApiKeyListItem.md +35 -0
  57. package/sdks/python/generated/emailagent_sdk_generated/docs/ApiKeyListResponse.md +29 -0
  58. package/sdks/python/generated/emailagent_sdk_generated/docs/CreateApiKeyRequest.md +30 -0
  59. package/sdks/python/generated/emailagent_sdk_generated/docs/CreateApiKeyRequestScopes.md +29 -0
  60. package/sdks/python/generated/emailagent_sdk_generated/docs/CreateDomainRequest.md +29 -0
  61. package/sdks/python/generated/emailagent_sdk_generated/docs/CreateInboxRequest.md +31 -0
  62. package/sdks/python/generated/emailagent_sdk_generated/docs/Domain.md +37 -0
  63. package/sdks/python/generated/emailagent_sdk_generated/docs/DomainListResponse.md +29 -0
  64. package/sdks/python/generated/emailagent_sdk_generated/docs/DomainResponse.md +29 -0
  65. package/sdks/python/generated/emailagent_sdk_generated/docs/DomainsApi.md +336 -0
  66. package/sdks/python/generated/emailagent_sdk_generated/docs/Email.md +43 -0
  67. package/sdks/python/generated/emailagent_sdk_generated/docs/EmailListResponse.md +29 -0
  68. package/sdks/python/generated/emailagent_sdk_generated/docs/EmailResponse.md +29 -0
  69. package/sdks/python/generated/emailagent_sdk_generated/docs/EmailsApi.md +353 -0
  70. package/sdks/python/generated/emailagent_sdk_generated/docs/ErrorResponse.md +29 -0
  71. package/sdks/python/generated/emailagent_sdk_generated/docs/Inbox.md +38 -0
  72. package/sdks/python/generated/emailagent_sdk_generated/docs/InboxListResponse.md +29 -0
  73. package/sdks/python/generated/emailagent_sdk_generated/docs/InboxResponse.md +29 -0
  74. package/sdks/python/generated/emailagent_sdk_generated/docs/InboxesApi.md +337 -0
  75. package/sdks/python/generated/emailagent_sdk_generated/docs/MetricsApi.md +83 -0
  76. package/sdks/python/generated/emailagent_sdk_generated/docs/MetricsData.md +35 -0
  77. package/sdks/python/generated/emailagent_sdk_generated/docs/MetricsResponse.md +29 -0
  78. package/sdks/python/generated/emailagent_sdk_generated/docs/OkResponse.md +29 -0
  79. package/sdks/python/generated/emailagent_sdk_generated/docs/PlanLimits.md +32 -0
  80. package/sdks/python/generated/emailagent_sdk_generated/docs/SendEmailRequest.md +32 -0
  81. package/sdks/python/generated/emailagent_sdk_generated/docs/UpdateEmailReadRequest.md +29 -0
  82. package/sdks/python/generated/emailagent_sdk_generated/docs/UpdateInboxRequest.md +29 -0
  83. package/sdks/python/generated/emailagent_sdk_generated/exceptions.py +216 -0
  84. package/sdks/python/generated/emailagent_sdk_generated/models/__init__.py +41 -0
  85. package/sdks/python/generated/emailagent_sdk_generated/models/api_key_created.py +113 -0
  86. package/sdks/python/generated/emailagent_sdk_generated/models/api_key_created_response.py +91 -0
  87. package/sdks/python/generated/emailagent_sdk_generated/models/api_key_list_item.py +123 -0
  88. package/sdks/python/generated/emailagent_sdk_generated/models/api_key_list_response.py +95 -0
  89. package/sdks/python/generated/emailagent_sdk_generated/models/create_api_key_request.py +93 -0
  90. package/sdks/python/generated/emailagent_sdk_generated/models/create_api_key_request_scopes.py +143 -0
  91. package/sdks/python/generated/emailagent_sdk_generated/models/create_domain_request.py +87 -0
  92. package/sdks/python/generated/emailagent_sdk_generated/models/create_inbox_request.py +91 -0
  93. package/sdks/python/generated/emailagent_sdk_generated/models/domain.py +134 -0
  94. package/sdks/python/generated/emailagent_sdk_generated/models/domain_list_response.py +95 -0
  95. package/sdks/python/generated/emailagent_sdk_generated/models/domain_response.py +91 -0
  96. package/sdks/python/generated/emailagent_sdk_generated/models/email.py +175 -0
  97. package/sdks/python/generated/emailagent_sdk_generated/models/email_list_response.py +95 -0
  98. package/sdks/python/generated/emailagent_sdk_generated/models/email_response.py +91 -0
  99. package/sdks/python/generated/emailagent_sdk_generated/models/error_response.py +87 -0
  100. package/sdks/python/generated/emailagent_sdk_generated/models/inbox.py +136 -0
  101. package/sdks/python/generated/emailagent_sdk_generated/models/inbox_list_response.py +95 -0
  102. package/sdks/python/generated/emailagent_sdk_generated/models/inbox_response.py +91 -0
  103. package/sdks/python/generated/emailagent_sdk_generated/models/metrics_data.py +110 -0
  104. package/sdks/python/generated/emailagent_sdk_generated/models/metrics_response.py +91 -0
  105. package/sdks/python/generated/emailagent_sdk_generated/models/ok_response.py +87 -0
  106. package/sdks/python/generated/emailagent_sdk_generated/models/plan_limits.py +93 -0
  107. package/sdks/python/generated/emailagent_sdk_generated/models/send_email_request.py +93 -0
  108. package/sdks/python/generated/emailagent_sdk_generated/models/update_email_read_request.py +87 -0
  109. package/sdks/python/generated/emailagent_sdk_generated/models/update_inbox_request.py +92 -0
  110. package/sdks/python/generated/emailagent_sdk_generated/rest.py +258 -0
  111. package/sdks/python/generated/emailagent_sdk_generated/test/__init__.py +0 -0
  112. package/sdks/python/generated/emailagent_sdk_generated/test/test_api_key_created.py +68 -0
  113. package/sdks/python/generated/emailagent_sdk_generated/test/test_api_key_created_response.py +52 -0
  114. package/sdks/python/generated/emailagent_sdk_generated/test/test_api_key_list_item.py +66 -0
  115. package/sdks/python/generated/emailagent_sdk_generated/test/test_api_key_list_response.py +56 -0
  116. package/sdks/python/generated/emailagent_sdk_generated/test/test_api_keys_api.py +59 -0
  117. package/sdks/python/generated/emailagent_sdk_generated/test/test_create_api_key_request.py +53 -0
  118. package/sdks/python/generated/emailagent_sdk_generated/test/test_create_api_key_request_scopes.py +50 -0
  119. package/sdks/python/generated/emailagent_sdk_generated/test/test_create_domain_request.py +52 -0
  120. package/sdks/python/generated/emailagent_sdk_generated/test/test_create_inbox_request.py +54 -0
  121. package/sdks/python/generated/emailagent_sdk_generated/test/test_domain.py +70 -0
  122. package/sdks/python/generated/emailagent_sdk_generated/test/test_domain_list_response.py +56 -0
  123. package/sdks/python/generated/emailagent_sdk_generated/test/test_domain_response.py +52 -0
  124. package/sdks/python/generated/emailagent_sdk_generated/test/test_domains_api.py +59 -0
  125. package/sdks/python/generated/emailagent_sdk_generated/test/test_email.py +79 -0
  126. package/sdks/python/generated/emailagent_sdk_generated/test/test_email_list_response.py +56 -0
  127. package/sdks/python/generated/emailagent_sdk_generated/test/test_email_response.py +52 -0
  128. package/sdks/python/generated/emailagent_sdk_generated/test/test_emails_api.py +59 -0
  129. package/sdks/python/generated/emailagent_sdk_generated/test/test_error_response.py +52 -0
  130. package/sdks/python/generated/emailagent_sdk_generated/test/test_inbox.py +68 -0
  131. package/sdks/python/generated/emailagent_sdk_generated/test/test_inbox_list_response.py +56 -0
  132. package/sdks/python/generated/emailagent_sdk_generated/test/test_inbox_response.py +52 -0
  133. package/sdks/python/generated/emailagent_sdk_generated/test/test_inboxes_api.py +59 -0
  134. package/sdks/python/generated/emailagent_sdk_generated/test/test_metrics_api.py +38 -0
  135. package/sdks/python/generated/emailagent_sdk_generated/test/test_metrics_data.py +72 -0
  136. package/sdks/python/generated/emailagent_sdk_generated/test/test_metrics_response.py +74 -0
  137. package/sdks/python/generated/emailagent_sdk_generated/test/test_ok_response.py +52 -0
  138. package/sdks/python/generated/emailagent_sdk_generated/test/test_plan_limits.py +58 -0
  139. package/sdks/python/generated/emailagent_sdk_generated/test/test_send_email_request.py +56 -0
  140. package/sdks/python/generated/emailagent_sdk_generated/test/test_update_email_read_request.py +52 -0
  141. package/sdks/python/generated/emailagent_sdk_generated/test/test_update_inbox_request.py +52 -0
  142. package/sdks/python/generated/emailagent_sdk_generated_README.md +140 -0
  143. package/sdks/python/openapitools.json +7 -0
  144. package/sdks/python/pyproject.toml +19 -0
  145. package/sdks/typescript/README.md +41 -0
  146. package/sdks/typescript/generated/.openapi-generator/FILES +41 -0
  147. package/sdks/typescript/generated/.openapi-generator/VERSION +1 -0
  148. package/sdks/typescript/generated/.openapi-generator-ignore +23 -0
  149. package/sdks/typescript/generated/package.json +21 -0
  150. package/sdks/typescript/generated/src/apis/APIKeysApi.ts +314 -0
  151. package/sdks/typescript/generated/src/apis/DomainsApi.ts +314 -0
  152. package/sdks/typescript/generated/src/apis/EmailsApi.ts +350 -0
  153. package/sdks/typescript/generated/src/apis/InboxesApi.ts +329 -0
  154. package/sdks/typescript/generated/src/apis/MetricsApi.ts +93 -0
  155. package/sdks/typescript/generated/src/apis/index.ts +7 -0
  156. package/sdks/typescript/generated/src/index.ts +5 -0
  157. package/sdks/typescript/generated/src/models/ApiKeyCreated.ts +123 -0
  158. package/sdks/typescript/generated/src/models/ApiKeyCreatedResponse.ts +74 -0
  159. package/sdks/typescript/generated/src/models/ApiKeyListItem.ts +121 -0
  160. package/sdks/typescript/generated/src/models/ApiKeyListResponse.ts +74 -0
  161. package/sdks/typescript/generated/src/models/CreateApiKeyRequest.ts +82 -0
  162. package/sdks/typescript/generated/src/models/CreateApiKeyRequestScopes.ts +45 -0
  163. package/sdks/typescript/generated/src/models/CreateDomainRequest.ts +66 -0
  164. package/sdks/typescript/generated/src/models/CreateInboxRequest.ts +82 -0
  165. package/sdks/typescript/generated/src/models/Domain.ts +152 -0
  166. package/sdks/typescript/generated/src/models/DomainListResponse.ts +74 -0
  167. package/sdks/typescript/generated/src/models/DomainResponse.ts +74 -0
  168. package/sdks/typescript/generated/src/models/Email.ts +222 -0
  169. package/sdks/typescript/generated/src/models/EmailListResponse.ts +74 -0
  170. package/sdks/typescript/generated/src/models/EmailResponse.ts +74 -0
  171. package/sdks/typescript/generated/src/models/ErrorResponse.ts +66 -0
  172. package/sdks/typescript/generated/src/models/Inbox.ts +159 -0
  173. package/sdks/typescript/generated/src/models/InboxListResponse.ts +74 -0
  174. package/sdks/typescript/generated/src/models/InboxResponse.ts +74 -0
  175. package/sdks/typescript/generated/src/models/MetricsData.ts +139 -0
  176. package/sdks/typescript/generated/src/models/MetricsResponse.ts +74 -0
  177. package/sdks/typescript/generated/src/models/OkResponse.ts +66 -0
  178. package/sdks/typescript/generated/src/models/PlanLimits.ts +93 -0
  179. package/sdks/typescript/generated/src/models/SendEmailRequest.ts +91 -0
  180. package/sdks/typescript/generated/src/models/UpdateEmailReadRequest.ts +66 -0
  181. package/sdks/typescript/generated/src/models/UpdateInboxRequest.ts +66 -0
  182. package/sdks/typescript/generated/src/models/index.ts +27 -0
  183. package/sdks/typescript/generated/src/runtime.ts +432 -0
  184. package/sdks/typescript/generated/tsconfig.esm.json +7 -0
  185. package/sdks/typescript/generated/tsconfig.json +16 -0
  186. package/sdks/typescript/openapitools.json +8 -0
  187. package/sdks/typescript/package.json +27 -0
  188. package/sdks/typescript/src/index.ts +138 -0
  189. package/sdks/typescript/tsconfig.json +14 -0
  190. package/sql/001_init.sql +143 -0
  191. package/sql/002_local_auth.sql +38 -0
  192. package/sql/003_domain_routes.sql +2 -0
  193. package/sql/004_reliability_primitives.sql +75 -0
  194. package/sql/005_auth_email_flows.sql +22 -0
  195. package/src/config.js +30 -0
  196. package/src/db.js +25 -0
  197. package/src/lib/api-auth.js +55 -0
  198. package/src/lib/auth.js +71 -0
  199. package/src/lib/csrf.js +46 -0
  200. package/src/lib/dodo.js +67 -0
  201. package/src/lib/email-templates.js +67 -0
  202. package/src/lib/idempotency.js +85 -0
  203. package/src/lib/mailgun.js +188 -0
  204. package/src/lib/plan.js +24 -0
  205. package/src/lib/rate-limit.js +43 -0
  206. package/src/lib/security.js +62 -0
  207. package/src/lib/session.js +21 -0
  208. package/src/lib/store.js +638 -0
  209. package/src/lib/transactional-mailer.js +54 -0
  210. package/src/lib/validation.js +30 -0
  211. package/src/routes/api.js +485 -0
  212. package/src/routes/app.js +699 -0
  213. package/src/routes/auth.js +404 -0
  214. package/src/routes/webhooks.js +257 -0
  215. package/src/server.js +79 -0
  216. package/src/views/pages/admin.ejs +58 -0
  217. package/src/views/pages/api-keys.ejs +56 -0
  218. package/src/views/pages/billing.ejs +71 -0
  219. package/src/views/pages/domains.ejs +106 -0
  220. package/src/views/pages/inboxes.ejs +127 -0
  221. package/src/views/pages/login.ejs +57 -0
  222. package/src/views/pages/metrics.ejs +34 -0
  223. package/src/views/pages/reset-password.ejs +19 -0
  224. package/src/views/partials/bottom.ejs +3 -0
  225. package/src/views/partials/csrf-field.ejs +3 -0
  226. package/src/views/partials/flash.ejs +3 -0
  227. package/src/views/partials/top.ejs +130 -0
@@ -0,0 +1,34 @@
1
+ ---
2
+ title: Errors
3
+ description: Error format and status code guidance.
4
+ ---
5
+
6
+ Error response shape:
7
+
8
+ ```json
9
+ {
10
+ "error": "message"
11
+ }
12
+ ```
13
+
14
+ Common status codes:
15
+
16
+ - `400` invalid request
17
+ - `401` missing/invalid bearer token
18
+ - `403` missing scope
19
+ - `404` resource not found
20
+ - `409` idempotency conflict
21
+ - `422` plan/validation limits
22
+ - `429` rate limited
23
+ - `500` provider/internal failure
24
+
25
+ Use idempotency keys and exponential backoff for retryable failures.
26
+
27
+ ## Inbound webhook statuses
28
+
29
+ When Mailgun forwards inbound mail to `/webhooks/mailgun/inbound`:
30
+
31
+ - `200` with `{"ok": true}`: inbound accepted and saved.
32
+ - `200` with `{"ok": true, "duplicate": true}`: duplicate delivery ignored.
33
+ - `202` with `{"ok": true, "ignored": true}`: recipient inbox not found.
34
+ - `401`: signature verification failed (`MAILGUN_WEBHOOK_SIGNING_KEY` mismatch).
@@ -0,0 +1,5 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none">
2
+ <rect width="64" height="64" rx="14" fill="#0c6f5c"/>
3
+ <path d="M16 22h32v20H16V22zm2 2v16h28V24H18z" fill="#ffffff"/>
4
+ <path d="M18 24l14 10 14-10" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
5
+ </svg>
@@ -0,0 +1,18 @@
1
+ ---
2
+ title: Idempotency
3
+ description: Safe retries for mutating operations.
4
+ ---
5
+
6
+ For mutating endpoints (`POST`, `PATCH`, `DELETE`), send:
7
+
8
+ ```http
9
+ Idempotency-Key: <unique_operation_key>
10
+ ```
11
+
12
+ Behavior:
13
+
14
+ - Same key + same payload: original response is replayed.
15
+ - Same key + different payload: `409` conflict.
16
+ - In-progress duplicate: `409` conflict.
17
+
18
+ Use deterministic keys from your agent action IDs for safe retries.
package/docs/index.mdx ADDED
@@ -0,0 +1,24 @@
1
+ ---
2
+ title: EmailAgent API
3
+ description: Email operations infrastructure for AI agents.
4
+ ---
5
+
6
+ EmailAgent gives agents a simple API to:
7
+
8
+ - Create and manage inboxes
9
+ - Send outbound emails
10
+ - Onboard and verify custom domains
11
+ - Manage API keys and scopes
12
+ - Track usage metrics
13
+
14
+ The canonical API contract is generated from:
15
+
16
+ - `openapi/openapi.yaml`
17
+
18
+ Base domains:
19
+
20
+ - App UI: `https://app.emailagent.dev`
21
+ - API: `https://api.emailagent.dev`
22
+ - Docs: `https://docs.emailagent.dev`
23
+
24
+ Start with [Quickstart](./quickstart).
@@ -0,0 +1,134 @@
1
+ ---
2
+ title: Quickstart
3
+ description: Create an API key, send email, and consume inbound email records.
4
+ ---
5
+
6
+ ## 0. Install SDKs (optional)
7
+
8
+ ```bash
9
+ npm install emailagent-sdk@0.1.0
10
+ pip install emailagent-sdk==0.1.0
11
+ ```
12
+
13
+ ## 1. Authenticate
14
+
15
+ Use a bearer API key from the dashboard.
16
+
17
+ ```bash
18
+ curl -X GET "https://api.emailagent.dev/api/v1/inboxes" \
19
+ -H "Authorization: Bearer <api_key>"
20
+ ```
21
+
22
+ ## 2. Create inbox
23
+
24
+ ```bash
25
+ curl -X POST "https://api.emailagent.dev/api/v1/inboxes" \
26
+ -H "Authorization: Bearer <api_key>" \
27
+ -H "Content-Type: application/json" \
28
+ -H "Idempotency-Key: create-inbox-agent-1" \
29
+ -d '{
30
+ "localPart": "agent-1",
31
+ "displayName": "Agent One"
32
+ }'
33
+ ```
34
+
35
+ ## 3. Send email
36
+
37
+ ```bash
38
+ curl -X POST "https://api.emailagent.dev/api/v1/emails/send" \
39
+ -H "Authorization: Bearer <api_key>" \
40
+ -H "Content-Type: application/json" \
41
+ -H "Idempotency-Key: send-welcome-001" \
42
+ -d '{
43
+ "inboxId": "<inbox_uuid>",
44
+ "to": "alice@example.com",
45
+ "subject": "Hello",
46
+ "text": "Welcome from your AI agent"
47
+ }'
48
+ ```
49
+
50
+ ## 4. List and mark inbound email
51
+
52
+ ```bash
53
+ curl -X GET "https://api.emailagent.dev/api/v1/emails?inboxId=<inbox_uuid>" \
54
+ -H "Authorization: Bearer <api_key>"
55
+ ```
56
+
57
+ ```bash
58
+ curl -X PATCH "https://api.emailagent.dev/api/v1/emails/<email_uuid>/read" \
59
+ -H "Authorization: Bearer <api_key>" \
60
+ -H "Content-Type: application/json" \
61
+ -H "Idempotency-Key: mark-read-001" \
62
+ -d '{"isRead": true}'
63
+ ```
64
+
65
+ ## 5. SDK examples
66
+
67
+ ```ts
68
+ import { EmailAgentClient } from 'emailagent-sdk';
69
+
70
+ const client = new EmailAgentClient({
71
+ apiKey: process.env.EMAILAGENT_API_KEY!,
72
+ baseUrl: 'https://api.emailagent.dev'
73
+ });
74
+
75
+ const inboxes = await client.listInboxes();
76
+ const inboxId = inboxes.data[0].id;
77
+ const emails = await client.listEmails({ inboxId });
78
+ if (emails.data.length) {
79
+ await client.updateEmailRead(emails.data[0].id, true, { idempotencyKey: 'mark-read-001' });
80
+ }
81
+ ```
82
+
83
+ ```python
84
+ from emailagent_sdk import EmailAgentClient
85
+
86
+ client = EmailAgentClient(api_key="<api_key>", base_url="https://api.emailagent.dev")
87
+ inboxes = client.list_inboxes()
88
+ inbox_id = inboxes["data"][0]["id"]
89
+ emails = client.list_emails(inbox_id=inbox_id)
90
+ if emails["data"]:
91
+ client.update_email_read(
92
+ email_id=emails["data"][0]["id"],
93
+ is_read=True,
94
+ idempotency_key="mark-read-001",
95
+ )
96
+ ```
97
+
98
+ ## 6. Shared-domain inbound route (manual setup)
99
+
100
+ For shared-domain inboxes (for example `agent@emailagent.dev`), configure this in Mailgun Routes:
101
+
102
+ - Expression: `match_recipient('.*@emailagent.dev')`
103
+ - Action 1: `forward('https://app.emailagent.dev/webhooks/mailgun/inbound')`
104
+ - Action 2: `stop()`
105
+
106
+ Also set `MAILGUN_WEBHOOK_SIGNING_KEY` in app environment to enforce webhook signature validation.
107
+
108
+ Expected successful webhook response:
109
+
110
+ ```json
111
+ {"ok": true}
112
+ ```
113
+
114
+ ## 7. Inbound troubleshooting
115
+
116
+ | Webhook response | Meaning | Action |
117
+ | --- | --- | --- |
118
+ | `401` | Invalid signature | Verify `MAILGUN_WEBHOOK_SIGNING_KEY` matches Mailgun webhook signing key |
119
+ | `202` with `ignored: true` | Recipient does not map to active inbox | Create/check inbox local part and domain in app |
120
+ | `200` with `duplicate: true` | Duplicate event received | No action needed; dedupe is working |
121
+
122
+ ## 8. Inbound smoke test
123
+
124
+ 1. Create inbox `agent@emailagent.dev` in app.
125
+ 2. Send email from external mailbox to that inbox.
126
+ 3. Confirm message appears in dashboard inbox view.
127
+ 4. Confirm same message appears via `GET /api/v1/emails?inboxId=<inbox_uuid>`.
128
+
129
+ ## 9. Check metrics
130
+
131
+ ```bash
132
+ curl -X GET "https://api.emailagent.dev/api/v1/metrics" \
133
+ -H "Authorization: Bearer <api_key>"
134
+ ```
@@ -0,0 +1,33 @@
1
+ # Landing Deployment (Netlify)
2
+
3
+ This project hosts the public landing page on the root domain.
4
+
5
+ ## Host mapping
6
+ - `emailagent.dev` -> Netlify landing site
7
+ - `www.emailagent.dev` -> redirect to `emailagent.dev`
8
+ - `app.emailagent.dev` -> Render app
9
+ - `api.emailagent.dev` -> Render API
10
+ - `docs.emailagent.dev` -> Docs host
11
+
12
+ ## Netlify setup
13
+ 1. Connect this GitHub repo to Netlify.
14
+ 2. Build settings:
15
+ - Build command: (leave empty)
16
+ - Publish directory: `landing`
17
+ 3. Add custom domain `emailagent.dev`.
18
+ 4. Add `www.emailagent.dev` and configure redirect to apex.
19
+ 5. In DNS provider, point apex and `www` records to Netlify targets.
20
+
21
+ ## Optional PR previews from GitHub Actions
22
+ Set these GitHub repository secrets:
23
+ - `NETLIFY_AUTH_TOKEN`
24
+ - `NETLIFY_SITE_ID`
25
+
26
+ When configured, pull requests touching `landing/**` trigger preview deploys.
27
+
28
+ ## Analytics setup
29
+ Edit `landing/index.html` and set values in `window.__landingAnalytics`:
30
+ - `plausibleDomain` for Plausible
31
+ - `ga4MeasurementId` for Google Analytics 4
32
+
33
+ `landing/main.js` tracks CTA events (`cta_click`) for both providers when available.
@@ -0,0 +1,5 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none">
2
+ <rect width="64" height="64" rx="14" fill="#0e7c66"/>
3
+ <path d="M14 22h36v20H14V22zm2 2v16h32V24H16z" fill="#fff"/>
4
+ <path d="M16 24l16 11 16-11" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
5
+ </svg>
@@ -0,0 +1,129 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>EmailAgent | Email Infrastructure for AI Agents</title>
7
+ <meta name="description" content="Provision inboxes, custom domains, API keys, and usage controls for AI agents with a simple API." />
8
+ <link rel="canonical" href="https://emailagent.dev" />
9
+ <meta property="og:title" content="EmailAgent" />
10
+ <meta property="og:description" content="Email infrastructure for AI agents." />
11
+ <meta property="og:type" content="website" />
12
+ <meta property="og:url" content="https://emailagent.dev" />
13
+ <meta name="twitter:card" content="summary_large_image" />
14
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
15
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
16
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
17
+ <link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=Sora:wght@500;600;700&display=swap" rel="stylesheet" />
18
+ <link rel="stylesheet" href="./styles.css" />
19
+ <script>
20
+ window.__landingAnalytics = {
21
+ plausibleDomain: "",
22
+ ga4MeasurementId: ""
23
+ };
24
+ </script>
25
+ <script defer src="./main.js"></script>
26
+ </head>
27
+ <body>
28
+ <div class="noise"></div>
29
+ <header class="topbar">
30
+ <a href="/" class="brand">EmailAgent</a>
31
+ <nav class="topnav">
32
+ <a href="#pricing">Pricing</a>
33
+ <a href="https://docs.emailagent.dev" data-cta="docs-nav">Docs</a>
34
+ <a class="button ghost" href="https://app.emailagent.dev/" data-cta="login-nav">Log in</a>
35
+ </nav>
36
+ </header>
37
+
38
+ <main>
39
+ <section class="hero">
40
+ <p class="eyebrow">Built for API-first teams</p>
41
+ <h1>Email infrastructure for AI agents</h1>
42
+ <p class="lead">
43
+ Create agent inboxes, send and receive emails, manage custom domains, and issue scoped API keys.
44
+ No mailbox UI complexity. Just reliable primitives your agents can call.
45
+ </p>
46
+ <div class="cta-row">
47
+ <a class="button primary" href="https://app.emailagent.dev/" data-cta="start-free-hero">Start for free</a>
48
+ <a class="button secondary" href="https://docs.emailagent.dev" data-cta="docs-hero">Read API docs</a>
49
+ </div>
50
+ <p class="status-note">Built for agent workflows, not human mailbox clients.</p>
51
+ </section>
52
+
53
+ <section class="features" aria-label="Core product features">
54
+ <article>
55
+ <h2>Inbox provisioning</h2>
56
+ <p>Programmatically create and manage inbox identities for each agent persona.</p>
57
+ </article>
58
+ <article>
59
+ <h2>Custom domains</h2>
60
+ <p>Onboard and verify domains with DNS mapping and Mailgun-backed deliverability.</p>
61
+ </article>
62
+ <article>
63
+ <h2>API keys + scopes</h2>
64
+ <p>Issue scoped keys for tools and agents with explicit permission boundaries.</p>
65
+ </article>
66
+ <article>
67
+ <h2>Usage controls</h2>
68
+ <p>Track limits and metrics so your agent workflows stay predictable and cost-aware.</p>
69
+ </article>
70
+ </section>
71
+
72
+ <section class="api-first">
73
+ <div>
74
+ <h2>API-first by design</h2>
75
+ <p>
76
+ Base your integration on OpenAPI and use official SDKs for TypeScript and Python.
77
+ Build fast, then scale reliably.
78
+ </p>
79
+ </div>
80
+ <div class="api-links">
81
+ <a href="https://docs.emailagent.dev" data-cta="docs-api-section">Open API documentation</a>
82
+ <a href="https://www.npmjs.com/package/emailagent-sdk" data-cta="npm-sdk">TypeScript SDK on npm</a>
83
+ <a href="https://pypi.org/project/emailagent-sdk/" data-cta="pypi-sdk">Python SDK on PyPI</a>
84
+ </div>
85
+ </section>
86
+
87
+ <section id="pricing" class="pricing">
88
+ <h2>Simple pricing</h2>
89
+ <div class="pricing-grid">
90
+ <article class="plan">
91
+ <h3>Free</h3>
92
+ <p class="price">$0<span>/month</span></p>
93
+ <ul>
94
+ <li>1 inbox on shared domain</li>
95
+ <li>0 custom domains</li>
96
+ <li>1,000 outbound emails/month</li>
97
+ <li>API access included</li>
98
+ </ul>
99
+ <a class="button secondary" href="https://app.emailagent.dev/" data-cta="start-free-pricing">Start free</a>
100
+ </article>
101
+ <article class="plan featured">
102
+ <p class="badge">Most popular</p>
103
+ <h3>Paid</h3>
104
+ <p class="price">$10<span>/month</span></p>
105
+ <ul>
106
+ <li>10 inboxes</li>
107
+ <li>1 custom domain</li>
108
+ <li>10,000 outbound emails/month</li>
109
+ <li>Upgrade in-app with Dodo Payments</li>
110
+ </ul>
111
+ <a class="button primary" href="https://app.emailagent.dev/app/billing" data-cta="upgrade-pricing">Upgrade</a>
112
+ </article>
113
+ </div>
114
+ </section>
115
+ </main>
116
+
117
+ <footer class="footer">
118
+ <div>
119
+ <strong>EmailAgent</strong>
120
+ <p>Email infrastructure for AI agents.</p>
121
+ </div>
122
+ <div class="footer-links">
123
+ <a href="/privacy.html" data-cta="privacy">Privacy</a>
124
+ <a href="/terms.html" data-cta="terms">Terms</a>
125
+ <a href="mailto:support@emailagent.dev" data-cta="support">support@emailagent.dev</a>
126
+ </div>
127
+ </footer>
128
+ </body>
129
+ </html>
@@ -0,0 +1,45 @@
1
+ (function () {
2
+ const analytics = window.__landingAnalytics || {};
3
+
4
+ function loadScript(src, attrs) {
5
+ const script = document.createElement('script');
6
+ script.src = src;
7
+ script.async = true;
8
+ Object.entries(attrs || {}).forEach(([k, v]) => script.setAttribute(k, v));
9
+ document.head.appendChild(script);
10
+ }
11
+
12
+ if (analytics.plausibleDomain) {
13
+ loadScript('https://plausible.io/js/script.js', {
14
+ defer: 'defer',
15
+ 'data-domain': analytics.plausibleDomain
16
+ });
17
+ }
18
+
19
+ if (analytics.ga4MeasurementId) {
20
+ const id = analytics.ga4MeasurementId;
21
+ loadScript(`https://www.googletagmanager.com/gtag/js?id=${encodeURIComponent(id)}`);
22
+ window.dataLayer = window.dataLayer || [];
23
+ window.gtag = window.gtag || function gtag() {
24
+ window.dataLayer.push(arguments);
25
+ };
26
+ window.gtag('js', new Date());
27
+ window.gtag('config', id);
28
+ }
29
+
30
+ function trackCta(label) {
31
+ if (window.plausible) {
32
+ window.plausible('cta_click', { props: { label: label } });
33
+ }
34
+ if (window.gtag) {
35
+ window.gtag('event', 'cta_click', { label: label });
36
+ }
37
+ }
38
+
39
+ document.querySelectorAll('[data-cta]').forEach((node) => {
40
+ node.addEventListener('click', function onClick() {
41
+ const label = node.getAttribute('data-cta') || 'unknown';
42
+ trackCta(label);
43
+ });
44
+ });
45
+ })();
@@ -0,0 +1,29 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>Privacy Policy | EmailAgent</title>
7
+ <meta name="description" content="Privacy policy for EmailAgent." />
8
+ <link rel="canonical" href="https://emailagent.dev/privacy.html" />
9
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
10
+ <link rel="stylesheet" href="./styles.css" />
11
+ </head>
12
+ <body>
13
+ <main style="max-width:900px;padding-top:28px;">
14
+ <a href="/" class="button ghost" style="display:inline-flex;margin-bottom:14px;">Back to home</a>
15
+ <section class="hero" style="padding:30px;">
16
+ <h1 style="font-size:40px;">Privacy Policy</h1>
17
+ <p class="lead">Last updated: February 9, 2026</p>
18
+ <h2 style="font-size:24px;">What we collect</h2>
19
+ <p class="lead">We collect account information (name, email), billing metadata, and email infrastructure metadata required to operate the service. We do not position EmailAgent as a personal email client.</p>
20
+ <h2 style="font-size:24px;">How we use data</h2>
21
+ <p class="lead">Data is used to provide inbox provisioning, domain onboarding, API key management, usage accounting, and abuse prevention.</p>
22
+ <h2 style="font-size:24px;">Subprocessors</h2>
23
+ <p class="lead">Email delivery and domain operations are handled through Mailgun. Billing is handled through Dodo Payments.</p>
24
+ <h2 style="font-size:24px;">Contact</h2>
25
+ <p class="lead">Questions: <a href="mailto:support@emailagent.dev">support@emailagent.dev</a></p>
26
+ </section>
27
+ </main>
28
+ </body>
29
+ </html>