Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
6a99a76
fix(tether): resolve a working Python 3 instead of hardcoding python3
AmirF194 Sep 1, 2026
12a9cbf
fix(auth): cascade configured OIDC logout (#984)
jiashuoz Sep 1, 2026
4299ea6
fix(auth): request Google's account chooser on legacy login (#987)
jiashuoz Sep 3, 2026
1c47458
chore(release): bump ts-sdk 5.9.0, cli 2.5.1, python 5.8.1 (#988)
jiashuoz Sep 3, 2026
55f1e7b
feat(sending): add durable provider authorization gate (#990)
jiashuoz Sep 3, 2026
01deae3
feat: onboarding acquisition survey (/welcome, users.acquisition_*, o…
jiashuoz Sep 3, 2026
8eb0256
fix(mcp): build the image from the committed lockfile (#994)
jiashuoz Sep 3, 2026
c26d934
feat(web): move protection save button to top right with dirty state …
jiashuoz Sep 4, 2026
d83566d
feat(blog): add 'Your approval gate shouldn't live in your agent's co…
jiashuoz Sep 4, 2026
dd352de
fix(sendramp): make a disabled sending ramp a true no-op (#996)
jiashuoz Sep 5, 2026
30089b9
feat(sending): compose ramp with protection gate (#992)
jiashuoz Sep 5, 2026
9c186cc
feat(outbound): require single-use provider authorization (B5) (#998)
jiashuoz Sep 5, 2026
2f6cdec
feat(outbound): enforce sending policy at fire time (B6) (#999)
jiashuoz Sep 5, 2026
0420cc3
feat(outbound): close the provider seam for every sender (B7) (#1000)
jiashuoz Sep 5, 2026
3791efb
feat(blog): add 'Your agent's inbox is storage, not transport' (#1007)
jiashuoz Sep 5, 2026
ce29e5b
fix(sendingpolicy): lock the agent FOR NO KEY UPDATE in the accept pa…
jiashuoz Sep 5, 2026
1999feb
docs(readme): highlight hosted service and MCP setup (#1008)
jiashuoz Sep 7, 2026
b6fb71d
docs(readme): use warm gold for logo and hosted button (#1010)
jiashuoz Sep 7, 2026
328b9e3
deps: bump the go-minor-patch group with 8 updates (#1004)
dependabot[bot] Sep 10, 2026
872c3a3
deps(web): bump the npm-minor-patch group in /web with 8 updates (#1003)
dependabot[bot] Sep 10, 2026
4e3f51b
deps(python): bump pydantic in /sdks/python in the uv-minor-patch gro…
dependabot[bot] Sep 10, 2026
9329eef
feat(blog): add 'Anyone in the world can put text in front of your ag…
jiashuoz Sep 10, 2026
49cc0c7
deps: bump the npm-minor-patch group with 3 updates (#1001)
dependabot[bot] Sep 10, 2026
1db0242
Merge remote-tracking branch 'origin/pr/980' into codex/fix-pr-980
jiashuoz Sep 10, 2026
288b598
fix(tether): route installer through Python resolver
jiashuoz Sep 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,19 @@ manually on every API change even though the template won't remind you.
bundled drive-by cleanup. CI must be green.
- **Coverage floors** only move up (see Testing strategy).
- **Postgres**: local dev runs on port **5433** (not 5432) via docker compose.
- **Row locks in multi-statement transactions**: an `INSERT` holds
`FOR KEY SHARE` on every row it references by foreign key until commit, and
`FOR UPDATE` conflicts with that. So a `SELECT … FOR UPDATE` on a parent row
taken *after* inserting a child in the same transaction deadlocks against a
concurrent insert for the same parent (v1.9.0: the accept transaction
inserted the message, then the gate locked the agent `FOR UPDATE`; two
parallel sends → SQLSTATE 40P01). Lock the parent `FOR NO KEY UPDATE`
(excludes updates, deletes and other lockers, coexists with key shares), or
lock it before the insert. The accept transaction's full lock order is in
`docs/design/async-message-pipeline.md`; any new lock on that path must be
checked against it, and any parallel-write path needs a concurrency test
(see `TestPrepareDoesNotDeadlockAgainstConcurrentInsert` for the
deterministic two-transaction shape).
- The Mailpit service in `docker-compose.yaml` is local-dev only — production
deployments must drop it and point `E2A_OUTBOUND_SMTP_*` at a real relay.

Expand Down
96 changes: 56 additions & 40 deletions README.md

Large diffs are not rendered by default.

10 changes: 9 additions & 1 deletion api/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1984,7 +1984,7 @@ components:
additionalProperties: true
properties:
code:
description: "Machine-branchable error code — the stable discriminator clients switch on. Open set: treat it as a string and tolerate unknown values, since new codes may be added over time (branch on the ones you handle, fall back to the HTTP status otherwise). Exact current vocabulary (machine-checked): unauthorized, forbidden, blocked_by_policy, invalid_request, invalid_cursor, invalid_filter, invalid_domain, invalid_slug, invalid_recipient, invalid_attachment, invalid_template, invalid_event_type, invalid_webhook_url, invalid_expires_at, invalid_scope, reserved_domain, too_many_recipients, template_render_failed, template_rendered_empty, recipient_suppressed, not_found, attachment_not_found, contact_not_found, engagement_not_found, import_batch_not_found, template_not_found, starter_template_not_found, gone, conflict, precondition_failed, agent_taken, domain_taken, alias_taken, address_in_trash, message_held, message_not_pending, message_not_yet_delivered, not_in_trash, purge_in_progress, send_in_progress, webhook_disabled, webhook_cooldown, domain_not_registered, domain_has_agents, domain_not_verified, inbound_mx_missing, limit_exceeded, rate_limited, contact_limit_reached, template_limit_reached, webhook_limit_reached, idempotency_in_flight, idempotency_key_reuse, payload_too_large, attachment_too_large, not_implemented, events_log_disabled, limits_unavailable, inbound_mx_check_failed, auth_unavailable, internal_error, method_not_allowed, unsupported_media_type, error. Grouped semantics: auth: unauthorized (401), forbidden (403), blocked_by_policy (403, outbound policy gate; experimental). Validation: invalid_request is the single canonical code for input-validation failures whether they arrive as 400 (malformed) or 422 (semantically invalid); field/resource-specific invalid_* refinements (invalid_cursor, invalid_filter, invalid_domain, invalid_slug, invalid_recipient, invalid_attachment, invalid_template, invalid_event_type, invalid_webhook_url, invalid_expires_at, invalid_scope), reserved_domain, too_many_recipients, template_render_failed, template_rendered_empty (all 400); recipient_suppressed (422). Not found: not_found (404) plus the *_not_found family (attachment_not_found, contact_not_found, engagement_not_found, import_batch_not_found, template_not_found, starter_template_not_found); gone (410, past retention). Conflict/state: conflict (409, generic), precondition_failed (412, optimistic-concurrency validator is stale), the *_taken family — the requested identifier is already claimed — (agent_taken, domain_taken, alias_taken, all 409), address_in_trash (409), message_held (409), message_not_pending (409), message_not_yet_delivered (409, retry after the source outbound message is sent), not_in_trash (409), purge_in_progress (409, permanent delete already claimed), send_in_progress (409), webhook_disabled (409), webhook_cooldown (409), domain_not_registered (400), domain_has_agents (400), domain_not_verified (400 on create-agent, 403 on send), inbound_mx_missing (400). Capacity: limit_exceeded (402, plan quota — see LimitExceededDetails), rate_limited (429, request rate — see RateLimitedDetails), contact_limit_reached, template_limit_reached and webhook_limit_reached (400, fixed per-account caps). Idempotency: idempotency_in_flight (409, wait then retry the byte-identical request), idempotency_key_reuse (422, caller bug — do not retry as-is). Size: payload_too_large (413, request body), attachment_too_large (413, inline fetch over the cap — use download_url). Availability: not_implemented (501, feature not available on this deployment), events_log_disabled (501), limits_unavailable (503), inbound_mx_check_failed (503), auth_unavailable (503, an auth backend — e.g. a delegated-token verifier or the identity store — could not judge the credential; retry). Server/fallback: internal_error (5xx), method_not_allowed (405), unsupported_media_type (415), and the generic code error for any otherwise-unmapped status."
description: "Machine-branchable error code — the stable discriminator clients switch on. Open set: treat it as a string and tolerate unknown values, since new codes may be added over time (branch on the ones you handle, fall back to the HTTP status otherwise). Exact current vocabulary (machine-checked): unauthorized, forbidden, blocked_by_policy, sending_paused, invalid_request, invalid_cursor, invalid_filter, invalid_domain, invalid_slug, invalid_recipient, invalid_attachment, invalid_template, invalid_event_type, invalid_webhook_url, invalid_expires_at, invalid_scope, reserved_domain, too_many_recipients, template_render_failed, template_rendered_empty, recipient_suppressed, not_found, attachment_not_found, contact_not_found, engagement_not_found, import_batch_not_found, template_not_found, starter_template_not_found, gone, conflict, precondition_failed, agent_taken, domain_taken, alias_taken, address_in_trash, message_held, message_not_pending, message_not_yet_delivered, not_in_trash, purge_in_progress, send_in_progress, webhook_disabled, webhook_cooldown, domain_not_registered, domain_has_agents, domain_not_verified, inbound_mx_missing, limit_exceeded, rate_limited, contact_limit_reached, template_limit_reached, webhook_limit_reached, idempotency_in_flight, idempotency_key_reuse, payload_too_large, attachment_too_large, not_implemented, events_log_disabled, limits_unavailable, inbound_mx_check_failed, auth_unavailable, internal_error, method_not_allowed, unsupported_media_type, error. Grouped semantics: auth: unauthorized (401), forbidden (403), blocked_by_policy (403, outbound policy gate; experimental), sending_paused (403, outbound sending is paused for the account by the platform abuse controls; queued mail is held, new sends are refused until an operator resumes; experimental). Validation: invalid_request is the single canonical code for input-validation failures whether they arrive as 400 (malformed) or 422 (semantically invalid); field/resource-specific invalid_* refinements (invalid_cursor, invalid_filter, invalid_domain, invalid_slug, invalid_recipient, invalid_attachment, invalid_template, invalid_event_type, invalid_webhook_url, invalid_expires_at, invalid_scope), reserved_domain, too_many_recipients, template_render_failed, template_rendered_empty (all 400); recipient_suppressed (422). Not found: not_found (404) plus the *_not_found family (attachment_not_found, contact_not_found, engagement_not_found, import_batch_not_found, template_not_found, starter_template_not_found); gone (410, past retention). Conflict/state: conflict (409, generic), precondition_failed (412, optimistic-concurrency validator is stale), the *_taken family — the requested identifier is already claimed — (agent_taken, domain_taken, alias_taken, all 409), address_in_trash (409), message_held (409), message_not_pending (409), message_not_yet_delivered (409, retry after the source outbound message is sent), not_in_trash (409), purge_in_progress (409, permanent delete already claimed), send_in_progress (409), webhook_disabled (409), webhook_cooldown (409), domain_not_registered (400), domain_has_agents (400), domain_not_verified (400 on create-agent, 403 on send), inbound_mx_missing (400). Capacity: limit_exceeded (402, plan quota — see LimitExceededDetails), rate_limited (429, request rate — see RateLimitedDetails), contact_limit_reached, template_limit_reached and webhook_limit_reached (400, fixed per-account caps). Idempotency: idempotency_in_flight (409, wait then retry the byte-identical request), idempotency_key_reuse (422, caller bug — do not retry as-is). Size: payload_too_large (413, request body), attachment_too_large (413, inline fetch over the cap — use download_url). Availability: not_implemented (501, feature not available on this deployment), events_log_disabled (501), limits_unavailable (503), inbound_mx_check_failed (503), auth_unavailable (503, an auth backend — e.g. a delegated-token verifier or the identity store — could not judge the credential; retry). Server/fallback: internal_error (5xx), method_not_allowed (405), unsupported_media_type (415), and the generic code error for any otherwise-unmapped status."
type: string
x-e2a-error-contracts:
address_in_trash:
Expand Down Expand Up @@ -2259,6 +2259,11 @@ components:
retryable: false
statuses:
- 409
sending_paused:
family: auth
retryable: false
statuses:
- 403
starter_template_not_found:
family: not_found
retryable: false
Expand Down Expand Up @@ -2317,6 +2322,7 @@ components:
- 400
x-experimental-values:
- blocked_by_policy
- sending_paused
details:
additionalProperties: true
description: Optional structured context, polymorphic by code. Treat it as an open object keyed off code; unknown codes and fields must be preserved.
Expand Down Expand Up @@ -2891,6 +2897,8 @@ components:
- submission.provider_rejected
- submission.local_retries_exhausted
- submission.cancelled
- submission.policy_budget_expired
- submission.sending_setup_expired
- delivery.recipient_server_accepted
- delivery.temporary_delay
- delivery.permanent_bounce
Expand Down
2 changes: 1 addition & 1 deletion assets/e2a-wordmark-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion assets/e2a-wordmark-light.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions assets/hosted-cta.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 17 additions & 0 deletions cli/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
# Changelog

## 2.5.1

Bug fix only. No flag, output-field, or exit-code meaning changes from 2.5.0.

**Fixed:** `e2a contacts import` no longer bakes a stray carriage return into
imported contact metadata. The CSV parser dropped `\r` unconditionally outside
a quoted field but appended it verbatim inside one, so a CRLF export from
Excel, Sheets, or a CRM containing a multi-line cell stored the cell's internal
line breaks as `\r\n`. Quoted fields now normalize the same way the unquoted
branch already did, matching the parser's documented RFC 4180 conformance.

**Documentation:** corrected the `--send-at` description in the README and in
this changelog's 2.2.0 entry. Both claimed a review hold *drops* the schedule;
in fact a scheduled send caught by a hold keeps its `send_at` — approving the
message submits at that instant if it is still in the future, or immediately if
it has already passed. No command behavior changed.

## 2.5.0

Additive only for every input that already succeeded in 2.4.0 — no flag,
Expand Down
4 changes: 2 additions & 2 deletions cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@e2a/cli",
"version": "2.5.0",
"version": "2.5.1",
"description": "CLI for e2a — give any AI agent a real, authenticated email inbox",
"bin": {
"e2a": "./dist/bin/e2a.js"
Expand Down Expand Up @@ -34,7 +34,7 @@
"@e2a/sdk": "^5.7.0"
},
"devDependencies": {
"@types/node": "^26.3.0",
"@types/node": "^26.4.1",
"@vitest/coverage-v8": "^4.1.11",
"typescript": "^7.0.2",
"vitest": "^4.1.10"
Expand Down
Loading
Loading