Skip to content

Conversation

@Huijiro
Copy link
Member

@Huijiro Huijiro commented Oct 27, 2025

Summary by CodeRabbit

  • New Features

    • Email sending now constructs RFC822 messages (including attachments) and returns a unique message ID.
    • Reply sending preserves threading headers (In-Reply-To/References) for proper conversation threading.
    • Sender address can be specified or sourced from agent defaults; recipient validation added.
  • Improvements

    • Centralized send/reply flow with improved async delivery.
    • Enhanced tracing and error reporting for email operations.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 27, 2025

Walkthrough

Email APIs were refactored to request/context-based async signatures returning Promise, centralizing MIME construction (MailComposer + attachments via fromDataType), adding OpenTelemetry spans, and moving send/sendReply responsibilities into src/apis/email.ts while src/io/email.ts now delegates to those methods. Types updated accordingly.

Changes

Cohort / File(s) Summary
Email API Implementation
src/apis/email.ts
New request-context async send and sendReply signatures returning Promise<string>. Builds RFC822 messages via MailComposer, converts attachments with fromDataType, validates recipients/from, posts message (Content-Type: message/rfc822, X-Agentuity-Message-Id), and records OpenTelemetry spans and errors. Exposes MailComposer/Attachment/EmailReply/Agent types.
Email IO Module (delegation)
src/io/email.ts
Removed manual MailComposer/attachment logic and auth-token extraction. send and sendReply now validate from and/or messageId minimally and delegate to context.email.send / context.email.sendReply. parseEmail left functionally unchanged.
Type Definitions
src/types.ts
EmailService signatures changed to send(req, context, to, email, from?) : Promise<string> and sendReply(req, context, inReplyTo, reply, from?) : Promise<string>. VectorSearchParams<T> constrained to T extends JsonObject = JsonObject.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant EmailIO as Email IO
    participant EmailAPI as Email API
    participant MailComp as MailComposer
    participant Telemetry as OpenTelemetry
    participant Server as Email Server

    Client->>EmailIO: send(req, ctx, to, email, from?)
    EmailIO->>EmailAPI: context.email.send(req, ctx, to, email, from?)
    EmailAPI->>Telemetry: start span (agentId)
    EmailAPI->>MailComp: build RFC822 message (+attachments via fromDataType)
    MailComp-->>EmailAPI: message/rfc822 (bytes)
    EmailAPI->>Server: POST /email/send (message/rfc822, X-Agentuity-Message-Id)
    Server-->>EmailAPI: 200 + messageId
    EmailAPI->>Telemetry: record messageId, end span
    EmailAPI-->>EmailIO: Promise<messageId>
    EmailIO-->>Client: Promise<messageId>

    alt Reply flow
      Client->>EmailIO: sendReply(req, ctx, inReplyTo, reply, from?)
      EmailIO->>EmailAPI: context.email.sendReply(...)
      EmailAPI->>Server: POST /email/2025-03-17/{agentId}/reply
    end

    alt Error
      Server-->>EmailAPI: error
      EmailAPI->>Telemetry: record exception, set status
      EmailAPI-->>EmailIO: throw Error
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Areas needing attention:
    • src/apis/email.ts: MIME building, attachment conversion (fromDataType), correct Content-Type and headers, and HTTP error propagation.
    • OpenTelemetry usage: span attributes, error recording, and proper finally/cleanup.
    • src/types.ts: interface signature changes affecting callers; verify all usages conform to new method shapes and generic constraint.
    • src/io/email.ts: ensure delegation preserves validation and error semantics.

Poem

🐰
I stitched the MIME with carrot care,
Traced each hop through spans in air,
From ctx to server, message sent—
Promise trails my scent,
A tiny rabbit's async flair.

Pre-merge checks and finishing touches

✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title 'Move email send to context' directly and concisely describes the main architectural change in the changeset. The primary objective across all modified files (src/apis/email.ts, src/io/email.ts, and src/types.ts) is to refactor email sending functionality by moving it from a direct implementation pattern to a context-based API pattern. The title accurately captures this core change without being overly broad or vague.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch email-ctx-send

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 267cdfc and 2627415.

📒 Files selected for processing (1)
  • src/apis/email.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
src/apis/**

📄 CodeRabbit inference engine (AGENT.md)

Place core API implementations under src/apis/ (email, discord, keyvalue, vector, objectstore)

Files:

  • src/apis/email.ts
{src,test}/**/!(*.d).ts

📄 CodeRabbit inference engine (AGENT.md)

{src,test}/**/!(*.d).ts: Use strict TypeScript and prefer unknown over any
Use ESM import/export syntax; avoid CommonJS require/module.exports
Use relative imports for internal modules
Keep imports organized (sorted, no unused imports)
Use tabs with a visual width of 2 spaces
Limit lines to a maximum of 80 characters
Use single quotes for strings
Use proper Error types; do not throw strings
Prefer template literals over string concatenation

Files:

  • src/apis/email.ts
src/apis/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/code-generation.mdc)

src/apis/**/*.ts: Do not hardcode generated prompt content (e.g., copyWriter) in source files; load it dynamically
Avoid overly complex TypeScript generics for generated content; prefer simple, maintainable types
Maintain type safety for dynamically loaded content by generating and referencing TypeScript definitions, with proper annotations for require() results
Do not use relative imports to generated artifacts; resolve via absolute node_modules paths or the package entry
Generated content is loaded at runtime, not build time; avoid static imports of generated modules
Prefer bracket notation for accessing slug-named properties with hyphens (e.g., prompts['slug-name'])
Avoid relative require('./generated/_index.js'); resolve absolute paths from process.cwd() into node_modules for generated assets

Files:

  • src/apis/email.ts
🧬 Code graph analysis (1)
src/apis/email.ts (5)
src/types.ts (3)
  • EmailService (671-699)
  • AgentRequest (1069-1089)
  • AgentContext (946-1064)
src/io/email.ts (4)
  • to (288-299)
  • EmailReply (222-242)
  • attachments (371-443)
  • messageId (272-274)
src/router/router.ts (1)
  • getTracer (61-66)
src/server/util.ts (1)
  • fromDataType (188-269)
src/apis/api.ts (1)
  • POST (253-270)
🔇 Additional comments (6)
src/apis/email.ts (6)

1-8: LGTM!

Imports are well-organized, use relative paths for internal modules, and follow ESM syntax as per coding guidelines.


48-55: LGTM!

Recipient and from-address validation is clear and appropriately rejects invalid inputs.


57-69: LGTM!

MailComposer setup correctly includes all necessary fields and provides sensible defaults for the sender name.


149-151: LGTM!

From-address validation is consistent with the send() method.


153-166: LGTM!

MailComposer correctly includes inReplyTo and references fields for proper email threading.


104-110: LGTM!

Error handling and span lifecycle management are implemented correctly in both methods.

Also applies to: 205-211


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

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/types.ts (1)

575-586: Fix type constraint mismatch in search() method signature.

The constraint on VectorSearchParams<T extends JsonObject> is incompatible with the unconstrained generic in search<T = unknown>. The method signature must be updated to match:

// src/apis/vector.ts line 222
async search<T extends JsonObject = JsonObject>(
	name: string,
	params: VectorSearchParams<T>
): Promise<VectorSearchResult[]>

Without this fix, callers passing explicit type parameters with non-JsonObject types will encounter TypeScript compilation errors.

🧹 Nitpick comments (4)
src/io/email.ts (2)

470-489: Avoid shadowing OpenTelemetry context import.

Parameter context: AgentContext shadows context from '@opentelemetry/api', inviting bugs if tracing is added later. Rename to ctx for clarity and consistency (other services use ctx).

-  async send(
-    req: AgentRequest,
-    context: AgentContext,
+  async send(
+    req: AgentRequest,
+    ctx: AgentContext,
     to: string[],
     email: EmailReply,
     from?: { name?: string; email?: string }
   ): Promise<string> {
-    const fromAddress = from?.email ?? this.toEmail();
+    const fromAddress = from?.email ?? this.toEmail();
     if (!fromAddress) {
       throw new Error('a valid from email address is required');
     }
-    return context.email.send(req, context, to, email, {
-      name: from?.name,
-      email: fromAddress,
-    });
+    return ctx.email.send(req, ctx, to, email, {
+      name: from?.name,
+      email: fromAddress,
+    });
   }

503-533: Drop unused toAddress check or document why it’s needed.

toAddress is computed only to throw if missing, but not used in the call. If reply routing doesn't require explicit to, remove this block to cut dead code; otherwise pass it through or document the rationale.

-    const toAddress = this.fromEmail();
-    if (!toAddress) {
-      throw new Error('cannot reply to an email without a sender address');
-    }
+    // If reply routing requires original sender, validate or pass through here.

Also apply the param rename to avoid context shadowing as above.

-  async sendReply(
-    req: AgentRequest,
-    context: AgentContext,
+  async sendReply(
+    req: AgentRequest,
+    ctx: AgentContext,
     reply: EmailReply,
     from?: { name?: string; email?: string }
   ): Promise<string> {
     const messageId = this.messageId();
     if (!messageId) {
       throw new Error('cannot reply to an email without a message ID');
     }
     const fromAddress = from?.email ?? this.toEmail();
     if (!fromAddress) {
       throw new Error('a valid from email address is required');
     }
-    return context.email.sendReply(
-      req, context, messageId,
+    return ctx.email.sendReply(
+      req, ctx, messageId,
       {
         subject: this.makeReplySubject(reply.subject),
         text: reply.text,
         html: reply.html,
         attachments: reply.attachments,
       },
       { name: from?.name, email: fromAddress }
     );
   }
src/apis/email.ts (2)

60-62: Error messages: standardize and include field name.

Use a consistent message like "from.email is required" to aid telemetry/search.

- throw new Error('a valid from email address is required');
+ throw new Error('from.email is required');

Also applies to: 169-171


24-30: Use AgentRequest.get() for metadata access: safer than direct object indexing.

The AgentRequest interface provides a dedicated get() method for accessing metadata values. Using req.get('email-auth-token') instead of indexing req.metadata?.['email-auth-token'] follows the designed API contract and is more resilient to implementation changes.

- const authToken = req.metadata?.['email-auth-token'] as string;
+ const authToken = req.get('email-auth-token') as string;

Also applies to lines 138-144.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 95347fe and 7f32a30.

📒 Files selected for processing (3)
  • src/apis/email.ts (3 hunks)
  • src/io/email.ts (3 hunks)
  • src/types.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
src/io/**

📄 CodeRabbit inference engine (AGENT.md)

I/O handlers (Discord, Slack, Email, SMS, Telegram) live under src/io/

Files:

  • src/io/email.ts
{src,test}/**/!(*.d).ts

📄 CodeRabbit inference engine (AGENT.md)

{src,test}/**/!(*.d).ts: Use strict TypeScript and prefer unknown over any
Use ESM import/export syntax; avoid CommonJS require/module.exports
Use relative imports for internal modules
Keep imports organized (sorted, no unused imports)
Use tabs with a visual width of 2 spaces
Limit lines to a maximum of 80 characters
Use single quotes for strings
Use proper Error types; do not throw strings
Prefer template literals over string concatenation

Files:

  • src/io/email.ts
  • src/apis/email.ts
  • src/types.ts
src/apis/**

📄 CodeRabbit inference engine (AGENT.md)

Place core API implementations under src/apis/ (email, discord, keyvalue, vector, objectstore)

Files:

  • src/apis/email.ts
src/apis/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/code-generation.mdc)

src/apis/**/*.ts: Do not hardcode generated prompt content (e.g., copyWriter) in source files; load it dynamically
Avoid overly complex TypeScript generics for generated content; prefer simple, maintainable types
Maintain type safety for dynamically loaded content by generating and referencing TypeScript definitions, with proper annotations for require() results
Do not use relative imports to generated artifacts; resolve via absolute node_modules paths or the package entry
Generated content is loaded at runtime, not build time; avoid static imports of generated modules
Prefer bracket notation for accessing slug-named properties with hyphens (e.g., prompts['slug-name'])
Avoid relative require('./generated/_index.js'); resolve absolute paths from process.cwd() into node_modules for generated assets

Files:

  • src/apis/email.ts
🧬 Code graph analysis (3)
src/io/email.ts (1)
src/router/data.ts (1)
  • email (243-253)
src/apis/email.ts (5)
src/types.ts (3)
  • EmailService (671-699)
  • AgentRequest (1069-1089)
  • AgentContext (946-1064)
src/io/email.ts (3)
  • to (288-299)
  • EmailReply (222-242)
  • attachments (371-443)
src/router/router.ts (1)
  • getTracer (61-66)
src/server/util.ts (1)
  • fromDataType (188-269)
src/apis/api.ts (1)
  • POST (253-270)
src/types.ts (2)
src/io/email.ts (1)
  • to (288-299)
src/router/data.ts (1)
  • email (243-253)
🔇 Additional comments (3)
src/apis/email.ts (1)

64-76: Keep first location; remove incorrect second location reference.

The refactor for lines 64-76 is valid—MailComposer accepts to as either a comma-separated string or an array. However, lines 173-186 do not contain a to field (that's a reply operation using inReplyTo and references), so the "Also applies to" claim is incorrect.

- to: normalizedTo.join(', '),
+ to: normalizedTo,

Likely an incorrect or invalid review comment.

src/types.ts (2)

676-684: Breaking change verification complete — no alignment issues found.

The interface signature change to Promise<string> is properly implemented:

  • EmailApi correctly implements the new return type
  • The single call site (src/io/email.ts:485) properly returns the promise to its caller
  • No orphaned implementations or mocks discovered

690-699: Test coverage needed: verify that Email.sendReply() return value is captured and used by handlers.

The implementation is correct—both Email.sendReply() (line 494) and Email.send() (line 472) properly return Promise<string> by propagating the result from context.email.sendReply() and context.email.send() respectively. However, there are no tests in test/io/email.test.ts (or elsewhere) verifying that the returned messageId is actually captured or used by handlers.

Confirm that tests exist for the return value handling, or add tests to verify handlers correctly use the returned message ID.

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

♻️ Duplicate comments (1)
src/apis/email.ts (1)

39-53: Reduce memory usage by streaming large attachments.

resp.data.buffer() loads entire attachment content into memory. Per the past review, DataHandler.stream() returns a ReadableStream, which can be passed to Nodemailer. However, Nodemailer expects Node.js streams, not Web ReadableStream.

Consider this approach to stream attachments:

 let attachments: Attachment[] = [];
 if (email.attachments) {
 	attachments = await Promise.all(
 		email.attachments.map(async (attachment) => {
 			const resp = await fromDataType(attachment.data);
+			const webStream = await resp.data.stream();
+			const nodeStream = webStream instanceof ReadableStream 
+				? Readable.fromWeb(webStream as any)
+				: webStream;
 			return {
 				filename: attachment.filename,
-				content: await resp.data.buffer(),
+				content: nodeStream,
 				contentType: resp.data.contentType,
 				contentDisposition:
 					attachment.contentDisposition ?? ('attachment' as const),
 			};
 		})
 	);
 }

You'll need to import Readable from Node.js stream module. This pattern also appears in sendReply() at lines 153-167 and should be extracted to a shared helper to avoid duplication.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7f32a30 and 3105709.

📒 Files selected for processing (2)
  • src/apis/api.ts (1 hunks)
  • src/apis/email.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
src/apis/**

📄 CodeRabbit inference engine (AGENT.md)

Place core API implementations under src/apis/ (email, discord, keyvalue, vector, objectstore)

Files:

  • src/apis/email.ts
  • src/apis/api.ts
{src,test}/**/!(*.d).ts

📄 CodeRabbit inference engine (AGENT.md)

{src,test}/**/!(*.d).ts: Use strict TypeScript and prefer unknown over any
Use ESM import/export syntax; avoid CommonJS require/module.exports
Use relative imports for internal modules
Keep imports organized (sorted, no unused imports)
Use tabs with a visual width of 2 spaces
Limit lines to a maximum of 80 characters
Use single quotes for strings
Use proper Error types; do not throw strings
Prefer template literals over string concatenation

Files:

  • src/apis/email.ts
  • src/apis/api.ts
src/apis/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/code-generation.mdc)

src/apis/**/*.ts: Do not hardcode generated prompt content (e.g., copyWriter) in source files; load it dynamically
Avoid overly complex TypeScript generics for generated content; prefer simple, maintainable types
Maintain type safety for dynamically loaded content by generating and referencing TypeScript definitions, with proper annotations for require() results
Do not use relative imports to generated artifacts; resolve via absolute node_modules paths or the package entry
Generated content is loaded at runtime, not build time; avoid static imports of generated modules
Prefer bracket notation for accessing slug-named properties with hyphens (e.g., prompts['slug-name'])
Avoid relative require('./generated/_index.js'); resolve absolute paths from process.cwd() into node_modules for generated assets

Files:

  • src/apis/email.ts
  • src/apis/api.ts
🧬 Code graph analysis (1)
src/apis/email.ts (5)
src/types.ts (3)
  • EmailService (671-699)
  • AgentRequest (1069-1089)
  • AgentContext (946-1064)
src/io/email.ts (4)
  • to (288-299)
  • EmailReply (222-242)
  • attachments (371-443)
  • messageId (272-274)
src/router/router.ts (1)
  • getTracer (61-66)
src/server/util.ts (1)
  • fromDataType (188-269)
src/apis/api.ts (1)
  • POST (253-270)
🪛 GitHub Actions: Run Tests
src/apis/api.ts

[error] 167-167: TS2322: Type 'Body | undefined' is not assignable to type 'BodyInit | null | undefined'. Type 'Buffer' is not assignable to type 'BodyInit'.

🔇 Additional comments (5)
src/apis/email.ts (5)

55-62: LGTM! Validation logic is correct.

The recipient normalization and validation ensure at least one valid recipient, and the from-email check prevents sending without a sender address.


64-75: LGTM! MailComposer configuration is correct.

The email composition properly maps all fields, and the fallback to ctx.agent.name for the sender name is a sensible default.


88-97: LGTM! Message sent as Buffer (not string).

The code correctly passes message (a Buffer) directly to POST without calling toString(), which would corrupt binary MIME content. This addresses the past review concern.


173-185: LGTM! Reply-specific MailComposer configuration is correct.

The inReplyTo and references fields are properly set for email threading, ensuring replies maintain conversation context.


198-207: LGTM! Message sent as Buffer with correct reply endpoint.

The message Buffer is passed directly to POST without conversion, and the reply-specific endpoint path is used correctly.

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

♻️ Duplicate comments (2)
src/apis/email.ts (2)

39-53: The past review comment about streaming attachments is still unresolved.

The current implementation still buffers entire attachments via resp.data.buffer() which can cause memory issues with large files. The past review comment correctly suggests using resp.data.stream() instead to stream attachment content directly to Nodemailer.


153-167: The past review comment about extracting duplicate attachment processing remains unresolved.

This attachment processing logic is identical to lines 39-53 in send(). The past review comment correctly suggests extracting this to a shared private helper method to reduce duplication.

🧹 Nitpick comments (1)
src/apis/email.ts (1)

138-143: LGTM, but consider extracting auth token validation.

The auth token extraction is correct and consistent with send(). However, this validation logic is duplicated. Consider extracting to a private helper method:

private extractAuthToken(req: AgentRequest): string {
  const authToken = req.metadata?.['email-auth-token'] as string;
  if (!authToken) {
    throw new Error(
      'email authorization token is required but not found in metadata'
    );
  }
  return authToken;
}

Then use: const authToken = this.extractAuthToken(req); in both methods.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3105709 and 267cdfc.

📒 Files selected for processing (1)
  • src/apis/email.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
src/apis/**

📄 CodeRabbit inference engine (AGENT.md)

Place core API implementations under src/apis/ (email, discord, keyvalue, vector, objectstore)

Files:

  • src/apis/email.ts
{src,test}/**/!(*.d).ts

📄 CodeRabbit inference engine (AGENT.md)

{src,test}/**/!(*.d).ts: Use strict TypeScript and prefer unknown over any
Use ESM import/export syntax; avoid CommonJS require/module.exports
Use relative imports for internal modules
Keep imports organized (sorted, no unused imports)
Use tabs with a visual width of 2 spaces
Limit lines to a maximum of 80 characters
Use single quotes for strings
Use proper Error types; do not throw strings
Prefer template literals over string concatenation

Files:

  • src/apis/email.ts
src/apis/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/code-generation.mdc)

src/apis/**/*.ts: Do not hardcode generated prompt content (e.g., copyWriter) in source files; load it dynamically
Avoid overly complex TypeScript generics for generated content; prefer simple, maintainable types
Maintain type safety for dynamically loaded content by generating and referencing TypeScript definitions, with proper annotations for require() results
Do not use relative imports to generated artifacts; resolve via absolute node_modules paths or the package entry
Generated content is loaded at runtime, not build time; avoid static imports of generated modules
Prefer bracket notation for accessing slug-named properties with hyphens (e.g., prompts['slug-name'])
Avoid relative require('./generated/_index.js'); resolve absolute paths from process.cwd() into node_modules for generated assets

Files:

  • src/apis/email.ts
🧬 Code graph analysis (1)
src/apis/email.ts (5)
src/types.ts (3)
  • EmailService (671-699)
  • AgentRequest (1069-1089)
  • AgentContext (946-1064)
src/io/email.ts (4)
  • to (288-299)
  • EmailReply (222-242)
  • attachments (371-443)
  • messageId (272-274)
src/router/router.ts (1)
  • getTracer (61-66)
src/server/util.ts (1)
  • fromDataType (188-269)
src/apis/api.ts (1)
  • POST (253-270)
🔇 Additional comments (6)
src/apis/email.ts (6)

1-8: LGTM!

The imports are well-organized and follow the coding guidelines. ESM syntax is used consistently, relative imports are used for internal modules, and type-only imports are properly applied.


24-29: LGTM!

The auth token extraction and validation is correct. The error message is clear and the check prevents downstream issues.


55-62: LGTM!

The validation logic is solid. Recipients are properly normalized and validated, and the from email requirement is clearly enforced with descriptive error messages.


169-171: LGTM!

The from email validation is consistent with the send() method and properly enforces the requirement.


173-187: LGTM!

The MailComposer configuration for replies is correct. The inReplyTo and references fields are properly set to maintain email threading, and the fallback for from.name using ctx.agent.name is consistent with the send() method.


188-225: Message sending logic mirrors send() method.

The message building and POST logic is solid with proper OpenTelemetry tracing and error handling. However, the same issues flagged in the send() method apply here:

  • Line 200: Should pass message directly instead of message.toString() (see earlier comment)
  • Line 216-217: Line length exceeds 80 characters (see earlier comment)

@Huijiro Huijiro merged commit 474222d into main Nov 4, 2025
3 checks passed
@Huijiro Huijiro deleted the email-ctx-send branch November 4, 2025 16:05
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.

2 participants