Commit Graph
423 Commits
Author SHA1 Message Date
Matthew Meszaros ee35138e37 feat: fix the generic IMAP client so it can actually connect and sync - assign the client before auth (was nil and would panic), check CONDSTORE after login where servers advertise it, request LIST-STATUS fields (folders were silently empty), and fetch 1:* instead of an empty SeqSet that panics inside go-imap 2026-07-11 17:30:20 +02:00
Matthew Meszaros 932b0bc856 feat: add the MAIL_TLS_INSECURE dev knob (netbind) so worker mail clients can skip TLS verification and, for SMTP, tolerate a server with no STARTTLS - local mailpit/dovecot only; production behavior is unchanged when the env var is unset 2026-07-11 17:30:20 +02:00
Matthew Meszaros 07a6777536 feat: email OAuth callback page gains a native-app fallback - when there is no web opener to postMessage (an ASWebAuthenticationSession has no popup parent) it redirects to warmbly://email-oauth with provider/code/state/error so the iOS app can finish the connect; web popup behavior is unchanged and the docs describe both delivery paths 2026-07-11 10:13:10 +02:00
Matthew Meszaros cc0871d1b8 feat: contacts search gains an additive lead_status filter plus per-status lead_counts on the first page when exactly one campaign_id is set - the SQL predicates reproduce the read-time status derivation exactly (unsubscribed > bounced > replied > active > pending via LATERAL bool_or rollups), invalid lead_status or multi-campaign combinations return 400, and the web types/table pick up the new lead_counts shape 2026-07-11 10:11:36 +02:00
Matthew Meszaros 430a31148a fix: campaign GetByID now selects and scans organization_id so the org gate in start/stop, the sender pool, advanced settings and tracking-domain verification stops 404ing every campaign (the field was always nil, failing campaignForOrg's non-nil org check) 2026-07-07 17:33:31 +02:00
Matthew Meszaros 3acb51df6c feat: add server-side status-bucket filtering to GET /campaigns (draft/active/paused/completed, paused matches every paused_* variant, invalid values 400) and a new GET /campaigns-overview endpoint returning status and per-folder counts, with the campaigns API reference and endpoint scope map updated 2026-07-07 09:40:27 +02:00
Matthew Meszaros 13f193d91e feat: unibox list filters - from now matches sender addresses by case-insensitive substring as documented, and a new uncategorized=true param returns only threads with no labels, documented in the unibox API reference 2026-07-07 05:56:47 +02:00
Matthew Meszaros 08699b1c88 feat: include the referral_reward_percent column in plan row scans so plan lookups stop failing after the referral rewards migration 2026-07-07 05:56:47 +02:00
Matthew Meszaros a20ba926cb feat: add native Apple/Google sign-in to the backend - POST /auth/apple and /auth/google exchange provider-signed ID tokens for sessions, GET /auth/providers exposes configured providers for app discovery, with a JWKS-verifying idtoken package, auth config, stable error codes, and API/security docs 2026-07-07 05:56:35 +02:00
Matthew Meszaros ad1d40fd2b test: cover the gmail/graph message mapping (read-state inversion, spam/category labels, unpadded base64url bodies, warmup and classification header surfacing), the imap header-flag parser, the graph MIME builder, and the human-behavior timing (sub-minute randomisation, daily volume factor, night-deferred and heavy-tailed engagement) 2026-07-04 11:45:01 +02:00
Matthew Meszaros f9142345ca feat: occasionally skip all positive warmup engagement on a message so a mailbox files but never opens some mail, avoiding a perfect every-message-engagement pattern while keeping spam-rescue and foldering 2026-07-04 11:38:23 +02:00
Matthew Meszaros 4ea9611510 feat: vary each mailbox's daily warmup volume by a stable per-day factor with occasional lighter days so a mailbox never sends an identical count every day 2026-07-04 11:36:47 +02:00
Matthew Meszaros 8b0f08c08d feat: throttle the worker reconciler to republish each mailbox at most every five minutes so the safety-net loop stops re-shipping every account's credentials over Kafka each tick, while onboarding and reassignment still load immediately 2026-07-04 11:36:47 +02:00
Matthew Meszaros 041ae5afd5 feat: resolve inbound bounce events back to the original campaign send by message id and record them idempotently through the deliverability pipeline (suppression, campaign progress, breaker), and document permanent-only bounce detection 2026-07-04 11:36:47 +02:00
Matthew Meszaros ab3c925eca feat: detect permanent NDRs worker-side from the synced bounce body across gmail/graph/imap and emit an INBOUND_BOUNCE event, giving api-sent mail its only bounce signal without adding SQL or S3 to the worker 2026-07-04 11:36:47 +02:00
Matthew Meszaros 7abde17c26 feat: add a conservative DSN bounce parser that extracts permanence, failed recipient, and original message id from delivery-status reports, treating only 5.x.x/failed as permanent so transient 4.x.x failures never over-suppress 2026-07-04 11:36:47 +02:00
Matthew Meszaros 1e8236d685 feat: only reply to warmup messages received between 45 minutes and 7 days ago so replies follow a plausible read, and document the human-behavior timing model in the warmup guide 2026-07-04 11:27:36 +02:00
Matthew Meszaros 3738f17643 feat: make warmup read engagement heavy-tailed up to an hour instead of uniform within four minutes and defer read/star/important actions into the recipient's waking hours so no pool mailbox reads mail at 3am 2026-07-04 11:27:36 +02:00
Matthew Meszaros 2a76428ecf feat: randomise the sub-minute second of every scheduled send, drop the campaign 5-minute grid rounding, and vary send spacing multiplicatively into bursts and lulls so fleet timing has no metronome or round-mark fingerprint 2026-07-04 11:27:36 +02:00
Matthew Meszaros 0e60971e57 feat: flag Graph junk-folder arrivals as Junk during delta sync so warmup spam-placement detection and placement tests see where the message landed 2026-07-04 09:30:27 +02:00
Matthew Meszaros b8e4002adb feat: fetch the warmup verify token and machine-reply headers via BODY.PEEK on IMAP sync and surface them as flag pseudo-headers, and join replies to the parent's thread instead of forking a new thread at every reply depth 2026-07-04 09:30:27 +02:00
Matthew Meszaros 3e4c3e9655 feat: write the caller's Message-ID header on SMTP sends so the recorded id matches the wire message for reply and bounce correlation, classify refused recipients as recipient-rejected instead of server-unreachable, and use the resolved host for the SMTP client handshake 2026-07-04 09:30:27 +02:00
Matthew Meszaros 1d4212c725 feat: key the Gmail messageId map by the Gmail message id so remove and label lookups match the add entry, and translate Gmail label transitions into internal flag add/remove events with the UNREAD inversion 2026-07-04 09:30:27 +02:00
Matthew Meszaros 5a7d791202 feat: fix the inverted UNREAD-to-Seen mapping in the Gmail message mapper, surface SPAM and CATEGORY_ labels for spam-placement and promotions detection, populate the snippet, and extract bodies from single-part payloads with unpadded base64url decoding 2026-07-04 09:30:27 +02:00
Matthew Meszaros 700a35da8d feat: hydrate full Gmail messages during history sync instead of mapping the id-only history stubs, skip 404s for messages deleted in-flight, and map non-API transport errors to a retryable mail error instead of silently returning nil 2026-07-04 09:30:27 +02:00
Matthew Meszaros 599f144364 feat: surface warmup and machine-reply/DSN headers from Gmail sync into flags for the reply and bounce classifier and match internet header names case-insensitively 2026-07-04 08:07:50 +02:00
Matthew Meszaros 4c0da59763 feat: categorize Graph warmup mail by surfacing the verify token into flags and filing it into the Warmbly folder, re-resolving the live message id from the immutable RFC Message-ID so post-move engagement actions never act on a stale id 2026-07-04 08:07:50 +02:00
Matthew Meszaros cb13c65d5d feat: load active mailboxes onto their assigned workers via a backend reconciler and immediately on onboarding, decrypting each account's credentials into the AddWorkerEmail payload, fixing gmail/outlook/smtp accounts that were assigned but never loaded 2026-07-04 08:07:49 +02:00
Matthew Meszaros 52c5f224fa feat: rebuild the provider oauth2 config locally on the worker so delegated mailbox tokens refresh, and ship BOX_ google/outlook client credentials to provisioned workers through the orchestrator env 2026-07-04 08:07:49 +02:00
Matthew Meszaros eb0a5654fd feat: persist the opaque per-folder Graph delta cursor in a new email_delta_links table via a repository and a GRAPH_DELTA_UPDATE consumer handler wired into the consumer service 2026-07-04 08:07:49 +02:00
Matthew Meszaros 049d751a11 feat: route the outlook provider through Microsoft Graph in the wmail worker with nil-guarded send/sync/new-email dispatch and a delta-cursor event, request delegated Graph OAuth scopes instead of the legacy IMAP/SMTP scopes, and always sync Outlook mailboxes 2026-07-04 08:07:49 +02:00
Matthew Meszaros 955ad1fc0c feat: add the internal/client/msgraph Graph mail client (RAW MIME sendMail, delta sync of inbox/junk, warmup move/mark/flag actions, RFC-message-id resolution, throttling-aware error mapping) plus the shared inbound classification-header list 2026-07-04 08:07:49 +02:00
Matthew Meszaros 1f2b228ec6 feat: wire the automation and sequence layout routes (PATCH /automations/:id/layout and /campaigns/:id/step-layout) behind the existing campaign and integration write permissions 2026-06-30 10:06:20 +02:00
Matthew Meszaros d4ead05456 feat: persist campaign sequence canvas coordinates with x/y columns (migration 000053) plus a bulk sequence-layout service/repo path that scopes by campaign owner and never bumps updated_at 2026-06-30 10:06:20 +02:00
Matthew Meszaros 73838cecf5 feat: add an unaudited automation node-layout endpoint handler/service/repo backed by an atomic jsonb x/y merge that leaves edges, config, and updated_at untouched 2026-06-30 10:06:19 +02:00
Matthew Meszaros ec6d47b39e feat: register GET /v1/me in the combined-auth protected route group reachable by API keys, OAuth, and JWT 2026-06-28 19:09:37 +02:00
Matthew Meszaros 5e94b945ff feat: add GetIdentity handler returning user, org, auth type, and granted scopes for GET /v1/me 2026-06-28 19:09:37 +02:00
Matthew Meszaros 5377374816 feat: add Identity model for the GET /v1/me caller-identity response shape 2026-06-28 19:09:37 +02:00
Matthew Meszaros 9dd37b0d62 Merge pull request #52 from warmbly/referral-credits
feat: implement referral program with credit-based rewards
2026-06-28 09:12:57 +02:00
Matthew Meszaros 22b75c9165 feat: implement ListByOrganization on the discount service test's fake redemption repo so the package typechecks under golangci-lint in CI 2026-06-28 06:35:42 +00:00
Matthew Meszaros 7e75394ab8 feat: decode the admin discount list and redemption cursors as opaque offset tokens, returning 400 on a malformed cursor instead of silently resetting to the first page 2026-06-28 05:58:25 +00:00
Matthew Meszaros 0d22e546a9 feat: update the discount service test's fake redemption repo to the new offset-based ListByCode signature 2026-06-28 05:58:25 +00:00
Matthew Meszaros 22bce66503 feat: thread an offset instead of a UUID cursor through the discount service ListRedemptions to match the offset-paged repository 2026-06-28 05:58:25 +00:00
Matthew Meszaros c964e54317 feat: fix admin discount-code and redemption pagination by replacing the broken dc.id keyset (mismatched against ORDER BY, skipping/duplicating rows) with offset paging that emits opaque o1_ next cursors 2026-06-28 05:58:25 +00:00
Matthew Meszaros 56fce77b0a feat: swap the admin discount search's query-bound UUID cursor for a handler-decoded Offset so the discount list's wire cursor stays opaque 2026-06-28 05:58:25 +00:00
Matthew Meszaros 88266a797e feat: add migration 000052 indexing discount_codes on (created_at DESC, id DESC) so the admin discount list avoids a seqscan+sort once an org runs many promo codes 2026-06-28 05:58:25 +00:00
Matthew Meszaros b71bef8e97 feat: drop the em dash from the welcome email copy to match the repo no-em-dash style rule 2026-06-28 05:31:23 +00:00
Matthew Meszaros 6c2ea71955 feat: capture base-shell render failures to Sentry in renderEmail so every transactional email template's render errors are observable 2026-06-28 05:31:23 +00:00
Matthew Meszaros 8373aebe99 feat: cover the refactored cancelled-deletion email shape with org and user template test cases 2026-06-28 05:31:23 +00:00
Matthew Meszaros fe03275dbe feat: apply email-client review fixes to the danger-zone deletion templates (move the callout background to the td so Outlook renders it, switch the self-closing br to plain br, and interpolate cancelled-deletion names through html/template) 2026-06-28 05:31:23 +00:00