Skip to content

Conversation

@neo773
Copy link
Member

@neo773 neo773 commented Jan 23, 2026

Adds support for multiple recipients in the Send Email workflow action

image

/closes #17383

@neo773 neo773 closed this Jan 23, 2026
@greptile-apps
Copy link
Contributor

greptile-apps bot commented Jan 23, 2026

Greptile Overview

Greptile Summary

This PR successfully extends the Send Email workflow action to support multiple recipients across To, CC, and BCC fields while maintaining backward compatibility with existing workflows using the single email field.

Key Changes:

  • Added EmailRecipientsInput component with dynamic row management for entering multiple email addresses
  • Updated WorkflowEditActionSendEmail to use three separate recipient input fields (To/CC/BCC)
  • Refactored SendEmailTool backend to normalize and validate multiple recipients from both new and legacy formats
  • Extended MessagingSendMessageService to handle email arrays for all providers (Google, Microsoft, SMTP)
  • Added toMicrosoftRecipients utility with comprehensive test coverage
  • Updated schemas and types across frontend, backend, and shared packages

Implementation Quality:

  • Clean separation of concerns with dedicated normalization and validation methods
  • Proper error handling with descriptive messages for invalid emails
  • Comprehensive Storybook stories including legacy format testing
  • Good test coverage for the Microsoft recipients utility

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk
  • The implementation is well-structured with proper backward compatibility, comprehensive validation, and good test coverage. The changes are additive and don't break existing functionality. Code follows repository conventions and patterns.
  • No files require special attention

Important Files Changed

Filename Overview
packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/EmailRecipientsInput.tsx New component for managing multiple email recipients with dynamic add/remove functionality
packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/WorkflowEditActionSendEmail.tsx Updated to support multiple recipients (To/CC/BCC) with backward compatibility for legacy email field
packages/twenty-server/src/engine/core-modules/tool/tools/send-email-tool/send-email-tool.schema.ts Added EmailRecipientsZodSchema with validation for to/cc/bcc arrays, maintains backward compatibility with legacy email field
packages/twenty-server/src/engine/core-modules/tool/tools/send-email-tool/send-email-tool.ts Refactored to support multiple recipients with normalizeRecipients and validateEmails methods, maintains backward compatibility
packages/twenty-server/src/modules/messaging/message-import-manager/services/messaging-send-message.service.ts Updated SendMessageInput type to accept string arrays for cc/bcc, uses toMicrosoftRecipients helper for Microsoft provider

Sequence Diagram

sequenceDiagram
    participant User
    participant EmailRecipientsInput
    participant WorkflowEditActionSendEmail
    participant SendEmailTool
    participant MessagingSendMessageService
    participant EmailProvider

    User->>WorkflowEditActionSendEmail: Configure email action
    WorkflowEditActionSendEmail->>EmailRecipientsInput: Render To/CC/BCC inputs
    Note over EmailRecipientsInput: Initializes with defaultValue<br/>or legacy email field
    
    User->>EmailRecipientsInput: Enter recipient emails
    EmailRecipientsInput->>EmailRecipientsInput: handleEntryChange()
    EmailRecipientsInput->>EmailRecipientsInput: Auto-add empty row if last filled
    EmailRecipientsInput->>WorkflowEditActionSendEmail: onChange(emails[])
    
    WorkflowEditActionSendEmail->>WorkflowEditActionSendEmail: handleFieldChange('recipients', {...})
    WorkflowEditActionSendEmail->>WorkflowEditActionSendEmail: saveAction (debounced)
    
    Note over User,EmailProvider: Workflow Execution Phase
    
    User->>SendEmailTool: Execute workflow
    SendEmailTool->>SendEmailTool: normalizeRecipients()
    Note over SendEmailTool: Handles both new recipients<br/>format and legacy email field
    
    SendEmailTool->>SendEmailTool: validateEmails()
    Note over SendEmailTool: Validates all to/cc/bcc emails
    
    alt Invalid emails found
        SendEmailTool-->>User: Return error with invalid emails
    end
    
    SendEmailTool->>MessagingSendMessageService: sendMessage({to[], cc[], bcc[]})
    
    alt Google Provider
        MessagingSendMessageService->>MessagingSendMessageService: Build MailComposer with arrays
        MessagingSendMessageService->>EmailProvider: Gmail API send
    else Microsoft Provider
        MessagingSendMessageService->>MessagingSendMessageService: toMicrosoftRecipients()
        MessagingSendMessageService->>EmailProvider: Microsoft Graph API send
    else SMTP Provider
        MessagingSendMessageService->>MessagingSendMessageService: Build MailComposer with arrays
        MessagingSendMessageService->>EmailProvider: SMTP send
    end
    
    EmailProvider-->>MessagingSendMessageService: Success
    MessagingSendMessageService-->>SendEmailTool: Email sent
    SendEmailTool-->>User: Success with recipient details
Loading

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.

1 file reviewed, 1 comment

Edit Code Review Agent Settings | Greptile


const nonEmptyValues = newEntries
.map((entry) => entry.value.trim())
.filter((value) => value.length > 0);
Copy link
Contributor

Choose a reason for hiding this comment

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

Use isNonEmptyString utility instead of manual check.

Suggested change
.filter((value) => value.length > 0);
.filter((value) => isNonEmptyString(value));

Context Used: Context from dashboard - Use the 'isNonEmptyString' utility function to check for non-empty strings instead of checking for e... (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/components/EmailRecipientsInput.tsx
Line: 66:66

Comment:
Use `isNonEmptyString` utility instead of manual check.

```suggestion
      .filter((value) => isNonEmptyString(value));
```

**Context Used:** Context from `dashboard` - Use the 'isNonEmptyString' utility function to check for non-empty strings instead of checking for e... ([source](https://app.greptile.com/review/custom-context?memory=1553f120-8908-4962-bc22-796896959d06))

<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>

How can I resolve this? If you propose a fix, please make it concise.

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.

1 issue found across 11 files

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="packages/twenty-shared/src/workflow/schemas/send-email-action-settings-schema.ts">

<violation number="1" location="packages/twenty-shared/src/workflow/schemas/send-email-action-settings-schema.ts:15">
P2: The schema now allows a Send Email action with no recipients at all (both `email` and `recipients` can be missing), which can lead to invalid workflows or runtime errors when sending. Add validation to require at least one recipient (legacy `email` or any of `recipients.to/cc/bcc`).</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

input: z.object({
connectedAccountId: z.string(),
email: z.string(),
email: z.string().optional(),
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Jan 23, 2026

Choose a reason for hiding this comment

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

P2: The schema now allows a Send Email action with no recipients at all (both email and recipients can be missing), which can lead to invalid workflows or runtime errors when sending. Add validation to require at least one recipient (legacy email or any of recipients.to/cc/bcc).

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/twenty-shared/src/workflow/schemas/send-email-action-settings-schema.ts, line 15:

<comment>The schema now allows a Send Email action with no recipients at all (both `email` and `recipients` can be missing), which can lead to invalid workflows or runtime errors when sending. Add validation to require at least one recipient (legacy `email` or any of `recipients.to/cc/bcc`).</comment>

<file context>
@@ -2,11 +2,18 @@ import { z } from 'zod';
     input: z.object({
       connectedAccountId: z.string(),
-      email: z.string(),
+      email: z.string().optional(),
+      recipients: workflowEmailRecipientsSchema.optional(),
       subject: z.string().optional(),
</file context>
Fix with Cubic

@github-actions
Copy link
Contributor

github-actions bot commented Jan 23, 2026

🚀 Preview Environment Ready!

Your preview environment is available at: http://bore.pub:39807

This environment will automatically shut down when the PR is closed or after 5 hours.

@neo773 neo773 reopened this Jan 23, 2026
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.

No files reviewed, no comments

Edit Code Review Agent Settings | Greptile

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.

[Workflow] Send email node - Allow multiple recipients

2 participants