diff --git a/packages/nodes-base/nodes/Google/Gmail/GenericFunctions.ts b/packages/nodes-base/nodes/Google/Gmail/GenericFunctions.ts index 0319df5678ad4..ae0a9e6e7e448 100644 --- a/packages/nodes-base/nodes/Google/Gmail/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Google/Gmail/GenericFunctions.ts @@ -166,19 +166,13 @@ export async function parseRawEmail( dataPropertyNameDownload: string, ): Promise { const messageEncoded = Buffer.from(messageData.raw, 'base64').toString('utf8'); - let responseData = await simpleParser(messageEncoded); + const responseData = await simpleParser(messageEncoded); const headers: IDataObject = {}; - // @ts-ignore for (const header of responseData.headerLines) { headers[header.key] = header.line; } - // @ts-ignore - responseData.headers = headers; - // @ts-ignore - responseData.headerLines = undefined; - const binaryData: IBinaryKeyData = {}; if (responseData.attachments) { const downloadAttachments = this.getNodeParameter( @@ -196,8 +190,6 @@ export async function parseRawEmail( ); } } - // @ts-ignore - responseData.attachments = undefined; } const mailBaseData: IDataObject = {}; @@ -205,14 +197,17 @@ export async function parseRawEmail( const resolvedModeAddProperties = ['id', 'threadId', 'labelIds', 'sizeEstimate']; for (const key of resolvedModeAddProperties) { - // @ts-ignore mailBaseData[key] = messageData[key]; } - responseData = Object.assign(mailBaseData, responseData); + const json = Object.assign({}, mailBaseData, responseData, { + headers, + headerLines: undefined, + attachments: undefined, + }) as IDataObject; return { - json: responseData as unknown as IDataObject, + json, binary: Object.keys(binaryData).length ? binaryData : undefined, } as INodeExecutionData; } @@ -390,6 +385,14 @@ export function prepareQuery( let timestamp = DateTime.fromISO(qs.receivedAfter as string).toSeconds(); const timestampLengthInMilliseconds1990 = 12; + if ( + !timestamp && + typeof qs.receivedAfter === 'number' && + qs.receivedAfter.toString().length < timestampLengthInMilliseconds1990 + ) { + timestamp = qs.receivedAfter; + } + if (!timestamp && (qs.receivedAfter as string).length < timestampLengthInMilliseconds1990) { timestamp = parseInt(qs.receivedAfter as string, 10); } diff --git a/packages/nodes-base/nodes/Google/Gmail/GmailTrigger.node.ts b/packages/nodes-base/nodes/Google/Gmail/GmailTrigger.node.ts index fe663c2490c87..2634463b2f7a2 100644 --- a/packages/nodes-base/nodes/Google/Gmail/GmailTrigger.node.ts +++ b/packages/nodes-base/nodes/Google/Gmail/GmailTrigger.node.ts @@ -194,8 +194,8 @@ export class GmailTrigger implements INodeType { let responseData; const now = Math.floor(DateTime.now().toSeconds()) + ''; - const startDate = (webhookData.lastTimeChecked as string) || now; - const endDate = now; + const startDate = (webhookData.lastTimeChecked as string) || +now; + const endDate = +now; const options = this.getNodeParameter('options', {}) as IDataObject; const filters = this.getNodeParameter('filters', {}) as IDataObject; @@ -273,7 +273,38 @@ export class GmailTrigger implements INodeType { ); } - webhookData.lastTimeChecked = endDate; + const getEmailDateAsSeconds = (email: IDataObject) => { + const { internalDate, date } = email; + return internalDate + ? +(internalDate as string) / 1000 + : +DateTime.fromJSDate(new Date(date as string)).toSeconds(); + }; + + const lastEmailDate = (responseData as IDataObject[]).reduce((lastDate, { json }) => { + const emailDate = getEmailDateAsSeconds(json as IDataObject); + return emailDate > lastDate ? emailDate : lastDate; + }, 0); + + const nextPollPossibleDuplicates = (responseData as IDataObject[]).reduce( + (duplicates, { json }) => { + const emailDate = getEmailDateAsSeconds(json as IDataObject); + return emailDate === lastEmailDate + ? duplicates.concat((json as IDataObject).id as string) + : duplicates; + }, + [] as string[], + ); + + const possibleDuplicates = (webhookData.possibleDuplicates as string[]) || []; + if (possibleDuplicates.length) { + responseData = (responseData as IDataObject[]).filter(({ json }) => { + const { id } = json as IDataObject; + return !possibleDuplicates.includes(id as string); + }); + } + + webhookData.possibleDuplicates = nextPollPossibleDuplicates; + webhookData.lastTimeChecked = lastEmailDate || endDate; if (Array.isArray(responseData) && responseData.length) { return [responseData as INodeExecutionData[]];