Expose sent message identifiers in workflow send-email step output (#22520)
## Context
First step toward thread-continuity / follow-up email steps in workflows
(email sequences). The outbound send pipeline already knows the sent
email's RFC-822 Message-ID, the provider thread id, and the persisted
message/thread records — but none of it was surfaced in the send-email
step output, so a later step had no way to reference the email that was
sent.
## What changed
- `saveMessagesWithinTransaction` also returns a `messageExternalId →
messageThreadId` map, and `saveMessagesAndEnqueueContactCreation`
returns the message/thread id maps (both other call sites ignore the
return value)
- `SentMessagePersistenceService.persistSentMessage` and
`SendEmailService.persistSentMessage` return the persisted `{ messageId,
messageThreadId }` (`undefined` when persistence is skipped or fails —
sending still succeeds)
- `SendEmailTool` result now includes `headerMessageId`,
`threadExternalId`, `messageId` and `messageThreadId`
- SEND_EMAIL step output schema (server + frontend) declares
`headerMessageId`/`messageId`/`messageThreadId` so they show up in the
variable picker; DRAFT_EMAIL keeps its success-only schema since draft
creation returns no identifiers yet
This already enables manual thread continuity today: wire
`{{sendEmailStep.headerMessageId}}` into a later email step's
In-Reply-To advanced field — the composer resolves the References chain
and provider thread from it.
## Tests
- New `send-email-tool.spec.ts` covering identifiers in the result,
persistence disabled, and persistence failure
- Extended save-messages spec with the new map, updated frontend
`computeStepOutputSchema` tests
<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/22520?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
This commit is contained in:
+37
-1
@@ -425,12 +425,48 @@ describe('computeStepOutputSchema', () => {
|
||||
});
|
||||
|
||||
describe('SEND_EMAIL step', () => {
|
||||
it('should return success boolean schema', () => {
|
||||
it('should return success and sent message identifier schema', () => {
|
||||
const result = computeStepOutputSchema({
|
||||
step: { type: 'SEND_EMAIL', settings: {} } as any,
|
||||
objectMetadataItems: [],
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
success: {
|
||||
isLeaf: true,
|
||||
type: FieldMetadataType.BOOLEAN,
|
||||
label: 'Success',
|
||||
value: true,
|
||||
},
|
||||
headerMessageId: {
|
||||
isLeaf: true,
|
||||
type: FieldMetadataType.TEXT,
|
||||
label: 'Message-ID header',
|
||||
value: '',
|
||||
},
|
||||
messageId: {
|
||||
isLeaf: true,
|
||||
type: FieldMetadataType.TEXT,
|
||||
label: 'Message record ID',
|
||||
value: '',
|
||||
},
|
||||
messageThreadId: {
|
||||
isLeaf: true,
|
||||
type: FieldMetadataType.TEXT,
|
||||
label: 'Message thread ID',
|
||||
value: '',
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('DRAFT_EMAIL step', () => {
|
||||
it('should return success boolean schema', () => {
|
||||
const result = computeStepOutputSchema({
|
||||
step: { type: 'DRAFT_EMAIL', settings: {} } as any,
|
||||
objectMetadataItems: [],
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
success: {
|
||||
isLeaf: true,
|
||||
|
||||
+29
-1
@@ -218,7 +218,35 @@ export const computeStepOutputSchema = ({
|
||||
return generateFormOutputSchema(formFields, objectMetadataItems);
|
||||
}
|
||||
|
||||
case 'SEND_EMAIL':
|
||||
case 'SEND_EMAIL': {
|
||||
return {
|
||||
success: {
|
||||
isLeaf: true,
|
||||
type: FieldMetadataType.BOOLEAN,
|
||||
label: 'Success',
|
||||
value: true,
|
||||
},
|
||||
headerMessageId: {
|
||||
isLeaf: true,
|
||||
type: FieldMetadataType.TEXT,
|
||||
label: 'Message-ID header',
|
||||
value: '',
|
||||
},
|
||||
messageId: {
|
||||
isLeaf: true,
|
||||
type: FieldMetadataType.TEXT,
|
||||
label: 'Message record ID',
|
||||
value: '',
|
||||
},
|
||||
messageThreadId: {
|
||||
isLeaf: true,
|
||||
type: FieldMetadataType.TEXT,
|
||||
label: 'Message thread ID',
|
||||
value: '',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
case 'DRAFT_EMAIL': {
|
||||
return {
|
||||
success: {
|
||||
|
||||
Reference in New Issue
Block a user