feat(messaging): sync draft emails and edit them in the thread composer (#22178)

Stop excluding drafts from sync across all three providers (Gmail DRAFT
label, Microsoft/IMAP Drafts folder) and add an isDraft boolean field on
Message so drafts are queryable by the API and AI agents.

Drafts render in the thread with a Draft tag; clicking one opens the
existing reply composer pre-filled with the draft's recipients, subject
and body, and Send reuses the existing send-email flow.

<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/22178?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. -->

---------

Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
This commit is contained in:
neo773
2026-06-30 16:37:53 +05:30
committed by GitHub
parent c4a6446757
commit 9f3ebaaf22
60 changed files with 2057 additions and 1100 deletions
@@ -2789,6 +2789,7 @@ type DuplicatedDashboard {
type SendEmailOutput {
success: Boolean!
error: String
messageThreadId: String
}
type Analytics {
@@ -4609,6 +4610,7 @@ input SendEmailInput {
subject: String!
body: String!
inReplyTo: String
draftMessageId: String
files: [SendEmailAttachmentInput!]
}
@@ -2453,6 +2453,7 @@ export interface DuplicatedDashboard {
export interface SendEmailOutput {
success: Scalars['Boolean']
error?: Scalars['String']
messageThreadId?: Scalars['String']
__typename: 'SendEmailOutput'
}
@@ -5611,6 +5612,7 @@ export interface DuplicatedDashboardGenqlSelection{
export interface SendEmailOutputGenqlSelection{
success?: boolean | number
error?: boolean | number
messageThreadId?: boolean | number
__typename?: boolean | number
__scalar?: boolean | number
}
@@ -6590,7 +6592,7 @@ export interface EditSsoInput {id: Scalars['UUID'],status: SSOIdentityProviderSt
export interface CreateCalendarEventInput {connectedAccountId: Scalars['String'],title: Scalars['String'],description?: (Scalars['String'] | null),location?: (Scalars['String'] | null),startsAt: Scalars['String'],endsAt: Scalars['String'],isFullDay?: (Scalars['Boolean'] | null),timeZone?: (Scalars['String'] | null),attendees?: (Scalars['String'] | null),sendInvitations?: (Scalars['Boolean'] | null),addConferencing?: (Scalars['Boolean'] | null)}
export interface SendEmailInput {connectedAccountId: Scalars['String'],to: Scalars['String'],cc?: (Scalars['String'] | null),bcc?: (Scalars['String'] | null),subject: Scalars['String'],body: Scalars['String'],inReplyTo?: (Scalars['String'] | null),files?: (SendEmailAttachmentInput[] | null)}
export interface SendEmailInput {connectedAccountId: Scalars['String'],to: Scalars['String'],cc?: (Scalars['String'] | null),bcc?: (Scalars['String'] | null),subject: Scalars['String'],body: Scalars['String'],inReplyTo?: (Scalars['String'] | null),draftMessageId?: (Scalars['String'] | null),files?: (SendEmailAttachmentInput[] | null)}
export interface SendEmailAttachmentInput {id: Scalars['String'],name: Scalars['String']}
@@ -5549,6 +5549,9 @@ export default {
"error": [
1
],
"messageThreadId": [
1
],
"__typename": [
1
]
@@ -11702,6 +11705,9 @@ export default {
"inReplyTo": [
1
],
"draftMessageId": [
1
],
"files": [
491
],