Skip to content

Comments

feat: add email verification based on spf/dkim/dmarc/logo verification#1622

Merged
ahmetskilinc merged 4 commits intoMail-0:stagingfrom
retrogtx:verified
Aug 25, 2025
Merged

feat: add email verification based on spf/dkim/dmarc/logo verification#1622
ahmetskilinc merged 4 commits intoMail-0:stagingfrom
retrogtx:verified

Conversation

@retrogtx
Copy link
Contributor

@retrogtx retrogtx commented Jul 4, 2025

verification.mp4

do not merge man need to add a different type of tick and need to test more and more

Summary by CodeRabbit

  • New Features
    • Added an email verification badge next to the sender's name in the mail display, indicating if an email is verified.
    • Users can now see a tooltip with details about email verification, including SPF, DKIM, DMARC, and BIMI checks.
  • Backend Enhancements
    • Introduced email authenticity and brand indicator (BIMI) validation for incoming emails.
    • Added support for retrieving and verifying raw email content via new API endpoints.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jul 4, 2025

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.

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

A new email verification feature was implemented, including backend logic to validate SPF, DKIM, DMARC, and BIMI, and a frontend badge indicating verification status. This involved adding methods for retrieving raw emails, a verification module, TRPC endpoints, and integrating a verification badge into the mail display UI.

Changes

File(s) Change Summary
apps/mail/components/mail/email-verification-badge.tsx Added EmailVerificationBadge React component to display email verification status using a tooltip and check icon.
apps/mail/components/mail/mail-display.tsx Integrated EmailVerificationBadge next to sender name in the mail display UI.
apps/server/src/lib/driver/google.ts Added getRawEmail method to GoogleMailManager to fetch and decode raw email content from Gmail API.
apps/server/src/lib/driver/types.ts Added getRawEmail method to MailManager interface.
apps/server/src/lib/email-verification.ts Created new module with exported verify function for SPF, DKIM, DMARC, and BIMI email validation.
apps/server/src/routes/chat.ts Added getRawEmail method to AgentRpcDO and ZeroAgent classes for retrieving raw email via mail driver.
apps/server/src/trpc/routes/mail.ts Added getRawEmail and verifyEmail query procedures to mailRouter for raw email retrieval and verification.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant MailDisplay
    participant EmailVerificationBadge
    participant TRPC_Client
    participant TRPC_Server
    participant Agent
    participant MailDriver
    participant VerificationModule

    User->>MailDisplay: View email
    MailDisplay->>EmailVerificationBadge: Render with messageId
    EmailVerificationBadge->>TRPC_Client: Query verifyEmail({id})
    TRPC_Client->>TRPC_Server: verifyEmail({id})
    TRPC_Server->>Agent: getRawEmail(id)
    Agent->>MailDriver: getRawEmail(id)
    MailDriver->>Agent: Return raw email
    Agent->>TRPC_Server: Return raw email
    TRPC_Server->>VerificationModule: verify(rawEmail)
    VerificationModule-->>TRPC_Server: {isVerified, logoUrl?}
    TRPC_Server->>TRPC_Client: Return verification result
    TRPC_Client->>EmailVerificationBadge: Show badge if verified
Loading

Poem

🐇
Hopping through headers, I check and I see,
SPF, DKIM, DMARC, and BIMI—
If all are in order, a blue badge will gleam,
Beside the sender, a trustful dream.
With every email, I verify true—
Secure and bright, just for you!
✉️✅

✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

PR Summary

Implements comprehensive email authentication with SPF, DKIM, DMARC, and BIMI verification, adding visual trust indicators in the mail interface.

  • Added new apps/server/src/lib/email-verification.ts with modular validation functions for each authentication protocol
  • Created EmailVerificationBadge component in apps/mail/components/mail/email-verification-badge.tsx to display verification status
  • Extended MailManager interface with getRawEmail() method in apps/server/src/lib/driver/types.ts to support verification checks
  • Added verification-related TRPC procedures in apps/server/src/trpc/routes/mail.ts for raw email access and verification
  • Integrated verification badge into mail-display.tsx alongside sender information

7 files reviewed, 5 comments
Edit PR Review Bot Settings | Greptile

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (2)
apps/server/src/lib/email-verification.ts (2)

354-354: Apply static analysis suggestions for optional chaining.

The static analysis tool correctly identified opportunities to use optional chaining for cleaner code.

-      if (logoUrl && logoUrl.startsWith('https://')) {
+      if (logoUrl?.startsWith('https://')) {
         return logoUrl;
       }
-        if (logoUrl && logoUrl.startsWith('https://')) {
+        if (logoUrl?.startsWith('https://')) {
           return logoUrl;
         }

Also applies to: 370-370


117-165: Enhance DKIM validation completeness.

The DKIM implementation has several limitations:

  1. Algorithm restriction: Only supports rsa-sha256, ignoring other valid algorithms
  2. Canonicalization: Assumes simple canonicalization, not handling relaxed or relaxed/simple
  3. Public key validation: No validation of the extracted public key format

Consider supporting additional algorithms and canonicalization methods for better compatibility.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 007d845 and 88bd6c6.

📒 Files selected for processing (7)
  • apps/mail/components/mail/email-verification-badge.tsx (1 hunks)
  • apps/mail/components/mail/mail-display.tsx (2 hunks)
  • apps/server/src/lib/driver/google.ts (1 hunks)
  • apps/server/src/lib/driver/types.ts (1 hunks)
  • apps/server/src/lib/email-verification.ts (1 hunks)
  • apps/server/src/routes/chat.ts (2 hunks)
  • apps/server/src/trpc/routes/mail.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (6)
apps/server/src/lib/driver/types.ts (1)
Learnt from: retrogtx
PR: Mail-0/Zero#1468
File: apps/server/src/trpc/routes/mail.ts:386-391
Timestamp: 2025-06-27T04:59:29.731Z
Learning: In apps/server/src/trpc/routes/mail.ts, the attachment processing logic conditionally handles mixed attachment types - it preserves existing File-like objects with arrayBuffer methods while only converting serialized attachments that need processing through toAttachmentFiles.
apps/server/src/trpc/routes/mail.ts (2)
Learnt from: retrogtx
PR: Mail-0/Zero#1468
File: apps/server/src/trpc/routes/mail.ts:386-391
Timestamp: 2025-06-27T04:59:29.731Z
Learning: In apps/server/src/trpc/routes/mail.ts, the attachment processing logic conditionally handles mixed attachment types - it preserves existing File-like objects with arrayBuffer methods while only converting serialized attachments that need processing through toAttachmentFiles.
Learnt from: retrogtx
PR: Mail-0/Zero#1468
File: apps/server/src/trpc/routes/mail.ts:331-331
Timestamp: 2025-06-28T03:56:09.376Z
Learning: In apps/server/src/trpc/routes/mail.ts, the user indicated they are not using ISO format for the scheduleAt parameter, despite the frontend code showing toISOString() usage in the ScheduleSendPicker component.
apps/server/src/lib/driver/google.ts (1)
Learnt from: retrogtx
PR: Mail-0/Zero#1468
File: apps/server/src/trpc/routes/mail.ts:386-391
Timestamp: 2025-06-27T04:59:29.731Z
Learning: In apps/server/src/trpc/routes/mail.ts, the attachment processing logic conditionally handles mixed attachment types - it preserves existing File-like objects with arrayBuffer methods while only converting serialized attachments that need processing through toAttachmentFiles.
apps/mail/components/mail/mail-display.tsx (1)
Learnt from: danteissaias
PR: Mail-0/Zero#618
File: apps/mail/components/mail/mail-iframe.tsx:12-12
Timestamp: 2025-04-07T20:46:11.697Z
Learning: In the Mail-0/Zero application, sender emails are guaranteed to be non-empty when passed to components that handle them, making additional empty string validation unnecessary.
apps/server/src/routes/chat.ts (1)
Learnt from: retrogtx
PR: Mail-0/Zero#1468
File: apps/server/src/trpc/routes/mail.ts:386-391
Timestamp: 2025-06-27T04:59:29.731Z
Learning: In apps/server/src/trpc/routes/mail.ts, the attachment processing logic conditionally handles mixed attachment types - it preserves existing File-like objects with arrayBuffer methods while only converting serialized attachments that need processing through toAttachmentFiles.
apps/server/src/lib/email-verification.ts (1)
Learnt from: retrogtx
PR: Mail-0/Zero#1468
File: apps/server/src/trpc/routes/mail.ts:386-391
Timestamp: 2025-06-27T04:59:29.731Z
Learning: In apps/server/src/trpc/routes/mail.ts, the attachment processing logic conditionally handles mixed attachment types - it preserves existing File-like objects with arrayBuffer methods while only converting serialized attachments that need processing through toAttachmentFiles.
🧬 Code Graph Analysis (3)
apps/mail/components/mail/email-verification-badge.tsx (2)
apps/mail/components/ui/tooltip.tsx (3)
  • Tooltip (72-72)
  • TooltipTrigger (72-72)
  • TooltipContent (72-72)
apps/mail/components/icons/icons.tsx (1)
  • CircleCheck (258-273)
apps/server/src/trpc/routes/mail.ts (3)
apps/server/src/trpc/trpc.ts (1)
  • activeDriverProcedure (43-77)
apps/server/src/lib/server-utils.ts (1)
  • getZeroAgent (15-20)
apps/server/src/lib/email-verification.ts (1)
  • verify (384-434)
apps/mail/components/mail/mail-display.tsx (1)
apps/mail/components/mail/email-verification-badge.tsx (1)
  • EmailVerificationBadge (11-41)
🪛 Biome (1.9.4)
apps/server/src/lib/email-verification.ts

[error] 354-354: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 370-370: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🔇 Additional comments (9)
apps/server/src/lib/driver/types.ts (1)

105-105: LGTM! Clean interface addition.

The getRawEmail method signature is well-designed with appropriate parameter and return types. It follows the existing naming conventions and integrates seamlessly with the interface.

apps/server/src/lib/driver/google.ts (1)

773-793: Excellent implementation following established patterns.

The getRawEmail method is well-implemented with:

  • Proper use of withErrorHandler for consistency
  • Correct Gmail API usage with format: 'raw'
  • Appropriate error handling for missing raw data
  • Correct base64 decoding for Gmail's response format

The implementation aligns perfectly with the existing codebase patterns and provides the necessary foundation for email verification.

apps/mail/components/mail/mail-display.tsx (2)

51-51: Clean import addition.

The EmailVerificationBadge import is properly placed and follows the existing import organization.


1456-1472: Excellent UI integration that preserves existing functionality.

The integration of the EmailVerificationBadge is well-executed:

  • Clean structural change from <span> to <div> container with flexbox layout
  • Proper spacing with gap-2 for visual separation
  • Existing click handler for sender research is preserved
  • Badge receives the correct messageId prop from emailData.id
  • No breaking changes to existing functionality

The implementation seamlessly adds the verification feature while maintaining the existing user experience.

apps/server/src/routes/chat.ts (1)

274-276: LGTM: Clean implementation following established patterns.

Both getRawEmail methods correctly follow the existing codebase patterns:

  • AgentRpcDO uses simple delegation like other methods
  • ZeroAgent includes the proper driver null check with meaningful error message

The implementation is consistent with the existing method signatures and error handling strategies.

Also applies to: 825-830

apps/server/src/trpc/routes/mail.ts (2)

398-408: LGTM: Simple and correct implementation.

The getRawEmail procedure follows the established pattern with proper input validation and clean delegation to the agent.


409-429: LGTM: Solid error handling and design.

The verifyEmail procedure demonstrates good practices:

  • Proper error handling with fallback return value
  • Dynamic import keeps verification logic modular
  • Error logging aids debugging
  • Safe default of { isVerified: false } on any failure
apps/mail/components/mail/email-verification-badge.tsx (1)

11-41: LGTM: Well-structured React component with proper query management.

The component demonstrates good practices:

  • Proper query configuration with reasonable caching (5 minutes) and retry policies
  • Conditional rendering that only shows badge when verified
  • Query disabled when messageId is undefined to prevent unnecessary requests
  • Clean UI structure with accessible tooltip

The implementation correctly integrates with the TRPC API and provides a good user experience.

apps/server/src/lib/email-verification.ts (1)

384-434: LGTM: Well-structured main verification function.

The main verify function demonstrates good architecture:

  • Parallel execution of validations for performance
  • Proper error handling with safe fallbacks
  • Clear logic requiring both authentication (SPF/DKIM/DMARC) and BIMI validation
  • Appropriate return type structure

The overall verification strategy aligns with email authentication best practices.

@retrogtx retrogtx marked this pull request as draft July 4, 2025 08:19
@JagjeevanAK
Copy link

worked on this topic good addition keep it up.

@github-actions
Copy link
Contributor

github-actions bot commented Aug 7, 2025

This PR has merge conflicts and has been open for more than 3 days. It will be automatically closed. Please resolve the conflicts and reopen the PR if you'd like to continue working on it.

@github-actions github-actions bot closed this Aug 7, 2025
@retrogtx retrogtx reopened this Aug 7, 2025
@jazzberry-ai
Copy link

jazzberry-ai bot commented Aug 7, 2025

Bug Report

Name Severity Example test case Description
Missing IPv6 CIDR validation error handling Medium An SPF record includes an ip6: mechanism with an invalid IPv6 CIDR range (e.g., ip6:invalid::address/64). The validateSPF function doesn't properly handle errors when parsing IPv6 CIDR ranges, which can lead to incorrect SPF validation results. Specifically, if ipv6CidrMatch throws an error, it is silently caught and false is returned. The code should re-throw or log the error.

Comments? Email us.

@github-actions
Copy link
Contributor

github-actions bot commented Aug 7, 2025

This PR has merge conflicts and has been open for more than 3 days. It will be automatically closed. Please resolve the conflicts and reopen the PR if you'd like to continue working on it.

@github-actions github-actions bot closed this Aug 7, 2025
@retrogtx retrogtx reopened this Aug 7, 2025
@jazzberry-ai
Copy link

jazzberry-ai bot commented Aug 7, 2025

Bug Report

Name Severity Example test case Description
SPF Validation - Infinite Loop High Set up a DNS record for example.com with v=spf1 include:example.com include:example.com all The validateSPF function may enter an infinite loop due to the visited set not accounting for different mechanisms with the same domain.
SPF Validation - Insecure IP matching High Use an IP address that starts with the same characters as the valid range. The ip4 and ip6 matching in validateSPF are too simplistic and vulnerable to bypasses.
BIMI Validation - Insecure Parent Domain Check Medium Set up a BIMI record on a parent domain that displays a logo for a different subdomain. The validateBIMI function checks for BIMI records on the parent domain, but doesn't validate that the logo is relevant to the subdomain.
BIMI Validation - Insecure VMC Validation Critical Set up a server with a self-signed certificate and use that URL in the VMC record. The validateVMC function only performs a HEAD request and doesn't validate the certificate chain or domain.
DMARC Validation - Missing Policy Enforcement Medium Send an email that fails SPF/DKIM but has a DMARC policy of reject. The validateDMARC function only checks for the existence of a DMARC record, but doesn't enforce the policy.

Comments? Email us.

@retrogtx retrogtx marked this pull request as ready for review August 11, 2025 20:37
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.

cubic analysis

2 issues found across 7 files • Review in cubic

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

export const EmailVerificationBadge: React.FC<EmailVerificationBadgeProps> = ({ messageId }) => {
const trpc = useTRPC();

const { data: verificationResult, isLoading, error, isError } = useQuery({
Copy link
Contributor

Choose a reason for hiding this comment

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

Rule violated: Prevent Side Effects or Logic Inside Render Functions or Loops

Do not place API calls or side-effectful hooks (like useQuery) inside render functions. Move useQuery to the top level of the component, outside of any render logic or loops, to prevent repeated side effects and performance issues.

Prompt for AI agents
Address the following comment on apps/mail/components/mail/email-verification-badge.tsx at line 14:

<comment>Do not place API calls or side-effectful hooks (like useQuery) inside render functions. Move useQuery to the top level of the component, outside of any render logic or loops, to prevent repeated side effects and performance issues.</comment>

<file context>
@@ -0,0 +1,41 @@
+import React from &#39;react&#39;;
+import { CircleCheck } from &#39;../icons/icons&#39;;
+import { Tooltip, TooltipContent, TooltipTrigger } from &#39;../ui/tooltip&#39;;
+import { useTRPC } from &#39;@/providers/query-provider&#39;;
+import { useQuery } from &#39;@tanstack/react-query&#39;;
+
+interface EmailVerificationBadgeProps {
+  messageId: string | undefined;
+}
</file context>

</span>
<div className="flex items-center gap-2">
<span
onClick={(e) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Rule violated: Detect React performance bottlenecks and rule breaking

Inline anonymous arrow function passed to the span’s onClick prop violates the performance rule ("Avoid defining anonymous functions directly inside JSX props" – Detect React performance bottlenecks). This function is recreated on every render, causing unnecessary re-renders of descendants and preventing potential memoization.

Prompt for AI agents
Address the following comment on apps/mail/components/mail/mail-display.tsx at line 1459:

<comment>Inline anonymous arrow function passed to the span’s onClick prop violates the performance rule (&quot;Avoid defining anonymous functions directly inside JSX props&quot; – Detect React performance bottlenecks). This function is recreated on every render, causing unnecessary re-renders of descendants and preventing potential memoization.</comment>

<file context>
@@ -1453,20 +1454,23 @@ const MailDisplay = ({ emailData, index, totalEmails, demo, threadAttachments }:
                     &lt;div className=&quot;flex w-full flex-col&quot;&gt;
                       &lt;div className=&quot;flex w-full items-center justify-between&quot;&gt;
                         &lt;div className=&quot;flex items-center gap-1&quot;&gt;
-                          &lt;span
-                            onClick={(e) =&gt; {
-                              e.stopPropagation();
-                              e.preventDefault();
-                              setResearchSender({
-                                name: emailData?.sender?.name || &#39;&#39;,
</file context>

@ahmetskilinc ahmetskilinc merged commit 71c57d1 into Mail-0:staging Aug 25, 2025
2 of 3 checks passed
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.

3 participants