n8n/packages/nodes-base/nodes/Google/Gmail/utils/replyToEmail.ts

155 lines
3.7 KiB
TypeScript

import uniq from 'lodash/uniq';
import { NodeOperationError, type IDataObject, type IExecuteFunctions } from 'n8n-workflow';
import type { IEmail } from '@utils/sendAndWait/interfaces';
import {
encodeEmail,
googleApiRequest,
prepareEmailAttachments,
prepareEmailBody,
prepareEmailsInput,
} from '../GenericFunctions';
import type { GmailMessage, GmailMessageMetadata, GmailUserProfile } from '../types';
export async function replyToEmail(
this: IExecuteFunctions,
gmailId: string,
options: IDataObject,
itemIndex: number,
nodeVersion: number,
) {
if (options.replyToSenderOnly && options.replyToRecipientsOnly) {
throw new NodeOperationError(
this.getNode(),
'Both "Reply to Sender Only" and "Reply to Recipient Only" cannot be enabled at the same time. Please select only one option.',
{ itemIndex },
);
}
let qs: IDataObject = {};
let cc = '';
let bcc = '';
if (options.ccList) {
cc = prepareEmailsInput.call(this, options.ccList as string, 'CC', itemIndex);
}
if (options.bccList) {
bcc = prepareEmailsInput.call(this, options.bccList as string, 'BCC', itemIndex);
}
let attachments: IDataObject[] = [];
if (options.attachmentsUi) {
attachments = await prepareEmailAttachments.call(
this,
options.attachmentsUi as IDataObject,
itemIndex,
);
if (attachments.length) {
qs = {
userId: 'me',
uploadType: 'media',
};
}
}
const endpoint = `/gmail/v1/users/me/messages/${gmailId}`;
qs.format = 'metadata';
const { payload, threadId } = (await googleApiRequest.call(
this,
'GET',
endpoint,
{},
qs,
)) as GmailMessageMetadata;
const subject =
payload.headers.filter(
(data: { [key: string]: string }) => data.name.toLowerCase() === 'subject',
)[0]?.value || '';
const messageIdGlobal =
payload.headers.filter(
(data: { [key: string]: string }) => data.name.toLowerCase() === 'message-id',
)[0]?.value || '';
const { emailAddress } = (await googleApiRequest.call(
this,
'GET',
'/gmail/v1/users/me/profile',
)) as GmailUserProfile;
const to: string[] = [];
const replyToSenderOnly =
options.replyToSenderOnly === undefined ? false : (options.replyToSenderOnly as boolean);
const replyToRecipientsOnly =
options.replyToRecipientsOnly === undefined
? false
: (options.replyToRecipientsOnly as boolean);
const prepareEmailString = (email: string) => {
if (email.includes(emailAddress)) return;
if (email.includes('<') && email.includes('>')) {
to.push(email);
} else {
to.push(`<${email}>`);
}
};
let replyToHeaderName = 'from';
if (nodeVersion >= 2.2 && payload.headers.some((h) => h.name.toLowerCase() === 'reply-to')) {
replyToHeaderName = 'reply-to';
}
for (const header of payload.headers) {
const headerName = (header.name || '').toLowerCase();
if (headerName === replyToHeaderName && !replyToRecipientsOnly) {
const replyToEmail = header.value;
if (replyToEmail.includes('<') && replyToEmail.includes('>')) {
to.push(replyToEmail);
} else {
to.push(`<${replyToEmail}>`);
}
}
if (headerName === 'to' && !replyToSenderOnly) {
const toEmails = header.value;
toEmails.split(',').forEach(prepareEmailString);
}
}
let from = '';
if (options.senderName) {
from = `${options.senderName as string} <${emailAddress}>`;
}
const toString = uniq(to).join(', ');
const email: IEmail = {
from,
to: toString,
cc,
bcc,
subject,
attachments,
inReplyTo: messageIdGlobal,
reference: messageIdGlobal,
...prepareEmailBody.call(this, itemIndex),
};
const body = {
raw: await encodeEmail(email),
threadId,
};
return (await googleApiRequest.call(
this,
'POST',
'/gmail/v1/users/me/messages/send',
body,
qs,
)) as GmailMessage;
}