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 |
|