diff --git a/apps/mail/components/mail/reply-composer.tsx b/apps/mail/components/mail/reply-composer.tsx
index 18e128139..0677ba753 100644
--- a/apps/mail/components/mail/reply-composer.tsx
+++ b/apps/mail/components/mail/reply-composer.tsx
@@ -5,7 +5,7 @@ import { useHotkeysContext } from 'react-hotkeys-hook';
import { useTRPC } from '@/providers/query-provider';
import { useMutation } from '@tanstack/react-query';
import { useSettings } from '@/hooks/use-settings';
-import { constructReplyBody } from '@/lib/utils';
+import { constructReplyBody, constructForwardBody } from '@/lib/utils';
import { useThread } from '@/hooks/use-threads';
import { serializeFiles } from '@/lib/schemas';
import { useDraft } from '@/hooks/use-drafts';
@@ -136,20 +136,28 @@ export default function ReplyCompose({ messageId }: ReplyComposeProps) {
? '
Sent via Zero
'
: '';
- const replyBody = constructReplyBody(
- data.message + zeroSignature,
- new Date(replyToMessage.receivedOn || '').toLocaleString(),
- replyToMessage.sender,
- toRecipients,
- replyToMessage.decodedBody,
- );
+ const emailBody = mode === 'forward'
+ ? constructForwardBody(
+ data.message + zeroSignature,
+ new Date(replyToMessage.receivedOn || '').toLocaleString(),
+ { ...replyToMessage.sender, subject: replyToMessage.subject },
+ toRecipients,
+ replyToMessage.decodedBody,
+ )
+ : constructReplyBody(
+ data.message + zeroSignature,
+ new Date(replyToMessage.receivedOn || '').toLocaleString(),
+ replyToMessage.sender,
+ toRecipients,
+ replyToMessage.decodedBody,
+ );
await sendEmail({
to: toRecipients,
cc: ccRecipients,
bcc: bccRecipients,
subject: data.subject,
- message: replyBody,
+ message: emailBody,
attachments: await serializeFiles(data.attachments),
fromEmail: aliases?.[0]?.email || userEmail,
headers: {
@@ -163,6 +171,8 @@ export default function ReplyCompose({ messageId }: ReplyComposeProps) {
'Thread-Id': replyToMessage?.threadId ?? '',
},
threadId: replyToMessage?.threadId,
+ isForward: mode === 'forward',
+ originalMessage: replyToMessage.decodedBody,
});
posthog.capture('Reply Email Sent');
diff --git a/apps/mail/lib/utils.ts b/apps/mail/lib/utils.ts
index 1ca64a421..7961024c5 100644
--- a/apps/mail/lib/utils.ts
+++ b/apps/mail/lib/utils.ts
@@ -287,8 +287,33 @@ export const constructReplyBody = (
On ${originalDate}, ${senderName} ${recipientEmails ? `<${recipientEmails}>` : ''} wrote:
-
- ${quotedMessage || ''}
+
+
+ `;
+};
+
+export const constructForwardBody = (
+ formattedMessage: string,
+ originalDate: string,
+ originalSender: Sender | undefined,
+ otherRecipients: Sender[],
+ quotedMessage?: string,
+) => {
+ const senderName = originalSender?.name || originalSender?.email || 'Unknown Sender';
+ const recipientEmails = otherRecipients.map((r) => r.email).join(', ');
+
+ return `
+
+
+ ${formattedMessage}
+
+
+
+ ---------- Forwarded message ----------
+ From: ${senderName} ${originalSender?.email ? `<${originalSender.email}>` : ''}
+ Date: ${originalDate}
+ Subject: ${originalSender?.subject || 'No Subject'}
+ To: ${recipientEmails || 'No Recipients'}
diff --git a/apps/mail/types/index.ts b/apps/mail/types/index.ts
index a2a17cb25..c1a3eca3b 100644
--- a/apps/mail/types/index.ts
+++ b/apps/mail/types/index.ts
@@ -55,6 +55,7 @@ export interface SidebarData {
export interface Sender {
name?: string;
email: string;
+ subject?: string;
}
export interface ParsedMessage {
@@ -113,14 +114,16 @@ export type ThreadProps = {
export interface IOutgoingMessage {
to: Sender[];
- cc?: Sender[];
- bcc?: Sender[];
subject: string;
message: string;
- attachments: File[];
- headers: Record;
+ attachments?: File[];
+ headers?: Record;
+ cc?: Sender[];
+ bcc?: Sender[];
threadId?: string;
fromEmail?: string;
+ isForward?: boolean;
+ originalMessage?: string;
}
export interface Note {
diff --git a/apps/server/src/lib/driver/google.ts b/apps/server/src/lib/driver/google.ts
index 1f25608fc..b6d766a1c 100644
--- a/apps/server/src/lib/driver/google.ts
+++ b/apps/server/src/lib/driver/google.ts
@@ -898,6 +898,8 @@ export class GoogleMailManager implements MailManager {
cc,
bcc,
fromEmail,
+ isForward = false,
+ originalMessage = null,
}: IOutgoingMessage) {
const msg = createMimeMessage();
@@ -990,10 +992,17 @@ export class GoogleMailManager implements MailManager {
msg.setSubject(subject);
- msg.addMessage({
- contentType: 'text/html',
- data: await sanitizeTipTapHtml(message.trim()),
- });
+ if (originalMessage) {
+ msg.addMessage({
+ contentType: 'text/html',
+ data: `${await sanitizeTipTapHtml(message.trim())}${originalMessage}`,
+ });
+ } else {
+ msg.addMessage({
+ contentType: 'text/html',
+ data: await sanitizeTipTapHtml(message.trim()),
+ });
+ }
if (headers) {
Object.entries(headers).forEach(([key, value]) => {
diff --git a/apps/server/src/trpc/routes/mail.ts b/apps/server/src/trpc/routes/mail.ts
index d5500b100..7eb182d73 100644
--- a/apps/server/src/trpc/routes/mail.ts
+++ b/apps/server/src/trpc/routes/mail.ts
@@ -273,6 +273,8 @@ export const mailRouter = router({
threadId: z.string().optional(),
fromEmail: z.string().optional(),
draftId: z.string().optional(),
+ isForward: z.boolean().optional(),
+ originalMessage: z.string().optional(),
}),
)
.mutation(async ({ ctx, input }) => {
diff --git a/apps/server/src/types.ts b/apps/server/src/types.ts
index cb35dd42d..ddf79858e 100644
--- a/apps/server/src/types.ts
+++ b/apps/server/src/types.ts
@@ -136,6 +136,8 @@ export interface IOutgoingMessage {
headers: Record;
threadId?: string;
fromEmail?: string;
+ isForward?: boolean;
+ originalMessage?: string | null;
}
export interface DeleteAllSpamResponse {
success: boolean;