Skip to content

Fix up cold email blocker for outlook#805

Merged
elie222 merged 5 commits intomainfrom
feat/microsoft-cold-email-blocker
Sep 20, 2025
Merged

Fix up cold email blocker for outlook#805
elie222 merged 5 commits intomainfrom
feat/microsoft-cold-email-blocker

Conversation

@elie222
Copy link
Owner

@elie222 elie222 commented Sep 20, 2025

Summary by CodeRabbit

  • New Features

    • Add date-range (after/before) and unread filters when browsing email threads.
    • “Mark as not cold” now works across providers (not just Gmail).
  • Improvements

    • Improved query construction for Gmail and Microsoft for more accurate filtering.
    • Pagination token propagation refined for smoother loading of additional threads.
    • Accounts page: each account now rendered as its own card with clearer actions.
  • Refactor

    • API requests switched to structured query parameters instead of single query strings.
  • Chores

    • Version bumped to v2.10.5.

@vercel
Copy link

vercel bot commented Sep 20, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Updated (UTC)
inbox-zero Ready Ready Preview Sep 20, 2025 7:21pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 20, 2025

Caution

Review failed

The pull request is closed.

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Replaces string-based thread queries with structured fields (after, before, isUnread) across API, validation, hooks, and provider adapters; removes the legacy Google threads controller; refactors cold-email action to use a provider-agnostic EmailProvider; updates UI query propagation and bumps version to v2.10.5.

Changes

Cohort / File(s) Summary
Threads API: route and validation
apps/web/app/api/threads/route.ts, apps/web/app/api/threads/validation.ts
Adds optional after/before/isUnread to threadsQuery schema and GET route; removes q field; forwards structured fields to getThreads.
Client query builders and pages
apps/web/hooks/useThreads.ts, apps/web/app/(app)/[emailAccountId]/mail/page.tsx, apps/web/app/(app)/[emailAccountId]/assistant/BulkRunRules.tsx
Build and propagate typed ThreadsQuery with after/before/isUnread; mutate query to include nextPageToken when present; BulkRunRules now supplies structured date/unread fields instead of a q string.
Email providers (Google/Microsoft)
apps/web/utils/email/google.ts, apps/web/utils/email/microsoft.ts
Google: compose Gmail query from multiple parts (from, after, before, is:unread, archive) and return undefined only when empty. Microsoft: replace free-text q search with OData filters for date range and unread.
Cold email action (provider-agnostic)
apps/web/utils/actions/cold-email.ts
Replace Gmail-specific flow with provider-agnostic EmailProvider; action context now includes provider; use provider methods to fetch/remove thread labels.
Controller removal
apps/web/app/api/google/threads/controller.ts
Removes the Google threads controller file and its exported functions/types (getThreads, getLabelIds, ThreadsResponse).
Mocks and formatting
apps/web/utils/__mocks__/email-provider.ts
Simplifies getThread mock to a single inline resolved object (formatting-only change).
UI account list layout
apps/web/app/(app)/accounts/page.tsx
Refactors account list rendering into a self-contained AccountItem Card per account and adjusts delete/view handling to use onAccountDeleted callback.
Version
version.txt
Bumps version string to v2.10.5.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant UI as Web UI
  participant API as /api/threads
  participant Validation as threadsQuery.parse
  participant Core as getThreads
  participant Prov as EmailProvider
  participant Ext as Email Service

  User->>UI: Request threads (after/before/isUnread)
  UI->>API: GET /api/threads?after&before&isUnread
  API->>Validation: parse(query with after/before/isUnread)
  Validation->>Core: getThreads({ after, before, isUnread, ... })
  Core->>Prov: getThreadsWithQuery(ThreadsQuery)
  alt Provider = Google
    Prov->>Prov: build Gmail q from parts (from, after, before, is:unread, -label:INBOX)
    Prov->>Ext: Gmail API threads.list(q=...)
  else Provider = Microsoft
    Prov->>Prov: build OData filter (receivedDateTime gt/lt, isRead eq false)
    Prov->>Ext: Graph API messages(filter=...)
  end
  Ext-->>Prov: threads + nextPageToken
  Prov-->>Core: threads result
  Core-->>API: { threads, nextPageToken }
  API-->>UI: JSON response
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

A rabbit hops through lines of code,
With dates and unread flags in tote,
No tangled q to make me roam,
Providers hum and bring threads home.
Version bumped — v2.10.5 — we tote a note. 🐇✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "Fix up cold email blocker for outlook" succinctly captures the primary intent of the PR — repairing the cold-email blocker for Microsoft/Outlook — and aligns with the key changes to the Microsoft email adapter, the cold-email action, and related threads query handling in this changeset; it is concise and focused rather than vague.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 64c017a and 46cb07d.

📒 Files selected for processing (2)
  • apps/web/app/(app)/accounts/page.tsx (1 hunks)
  • version.txt (1 hunks)

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 issues found across 11 files

Prompt for AI agents (all 3 issues)

Understand the root cause of the following 3 issues and fix them.


<file name="apps/web/hooks/useThreads.ts">

<violation number="1" location="apps/web/hooks/useThreads.ts:26">
Passing query as any to URLSearchParams will include keys with undefined values (e.g., limit=undefined, type=undefined), altering intended nullish handling and weakening type safety. Filter out nullish keys and stringify values before building the query string.</violation>
</file>

<file name="apps/web/app/api/threads/validation.ts">

<violation number="1" location="apps/web/app/api/threads/validation.ts:9">
Empty string (?after=) causes Invalid Date and a 400; preprocess &#39;&#39; to undefined so the filter is ignored instead of failing.</violation>

<violation number="2" location="apps/web/app/api/threads/validation.ts:10">
Empty string (?before=) will fail date coercion; preprocess &#39;&#39; to undefined to skip the filter.</violation>
</file>

React with 👍 or 👎 to teach cubic. Mention @cubic-dev-ai to give feedback, ask questions, or re-run the review.

};

// biome-ignore lint/suspicious/noExplicitAny: params
const url = `/api/threads?${new URLSearchParams(query as any).toString()}`;
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Sep 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Passing query as any to URLSearchParams will include keys with undefined values (e.g., limit=undefined, type=undefined), altering intended nullish handling and weakening type safety. Filter out nullish keys and stringify values before building the query string.

Prompt for AI agents
Address the following comment on apps/web/hooks/useThreads.ts at line 26:

<comment>Passing query as any to URLSearchParams will include keys with undefined values (e.g., limit=undefined, type=undefined), altering intended nullish handling and weakening type safety. Filter out nullish keys and stringify values before building the query string.</comment>

<file context>
@@ -15,11 +16,14 @@ export function useThreads({
+  };
+
+  // biome-ignore lint/suspicious/noExplicitAny: params
+  const url = `/api/threads?${new URLSearchParams(query as any).toString()}`;
   const { data, isLoading, error, mutate } = useSWR&lt;ThreadsResponse&gt;(url, {
     refreshInterval,
</file context>
Fix with Cubic

nextPageToken: z.string().nullish(),
labelId: z.string().nullish(), // For Google
after: z.coerce.date().nullish(),
before: z.coerce.date().nullish(),
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Sep 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty string (?before=) will fail date coercion; preprocess '' to undefined to skip the filter.

Prompt for AI agents
Address the following comment on apps/web/app/api/threads/validation.ts at line 10:

<comment>Empty string (?before=) will fail date coercion; preprocess &#39;&#39; to undefined to skip the filter.</comment>

<file context>
@@ -4,8 +4,10 @@ export const threadsQuery = z.object({
   nextPageToken: z.string().nullish(),
   labelId: z.string().nullish(), // For Google
+  after: z.coerce.date().nullish(),
+  before: z.coerce.date().nullish(),
+  isUnread: z.coerce.boolean().nullish(),
 });
</file context>
Fix with Cubic

q: z.string().nullish(),
nextPageToken: z.string().nullish(),
labelId: z.string().nullish(), // For Google
after: z.coerce.date().nullish(),
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Sep 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty string (?after=) causes Invalid Date and a 400; preprocess '' to undefined so the filter is ignored instead of failing.

Prompt for AI agents
Address the following comment on apps/web/app/api/threads/validation.ts at line 9:

<comment>Empty string (?after=) causes Invalid Date and a 400; preprocess &#39;&#39; to undefined so the filter is ignored instead of failing.</comment>

<file context>
@@ -4,8 +4,10 @@ export const threadsQuery = z.object({
-  q: z.string().nullish(),
   nextPageToken: z.string().nullish(),
   labelId: z.string().nullish(), // For Google
+  after: z.coerce.date().nullish(),
+  before: z.coerce.date().nullish(),
+  isUnread: z.coerce.boolean().nullish(),
</file context>
Fix with Cubic

@elie222 elie222 merged commit 4a77d7f into main Sep 20, 2025
10 of 12 checks passed
@elie222 elie222 deleted the feat/microsoft-cold-email-blocker branch September 20, 2025 19:18
@coderabbitai coderabbitai bot mentioned this pull request Oct 12, 2025
@coderabbitai coderabbitai bot mentioned this pull request Dec 18, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

Comments