Skip to content

Commit bbf463a

Browse files
committed
12336 updating to include some gmail email sync error handling
1 parent dc0401e commit bbf463a

File tree

3 files changed

+83
-15
lines changed

3 files changed

+83
-15
lines changed

packages/twenty-server/src/modules/messaging/message-import-manager/drivers/gmail/utils/parse-gmail-message.util.ts

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,20 @@ import { getAttachmentData } from 'src/modules/messaging/message-import-manager/
77
import { getBodyData } from 'src/modules/messaging/message-import-manager/drivers/gmail/utils/get-body-data.util';
88
import { getPropertyFromHeaders } from 'src/modules/messaging/message-import-manager/drivers/gmail/utils/get-property-from-headers.util';
99

10+
/**
11+
* Safely parses an email address string using addressparser
12+
* Returns undefined if parsing fails
13+
*/
14+
const safeParseAddress = (address: string | undefined) => {
15+
if (!address) return undefined;
16+
try {
17+
return addressparser(address);
18+
} catch (error) {
19+
console.error('Error parsing address:', error);
20+
return undefined;
21+
}
22+
};
23+
1024
export const parseGmailMessage = (message: gmail_v1.Schema$Message) => {
1125
const subject = getPropertyFromHeaders(message, 'Subject');
1226
const rawFrom = getPropertyFromHeaders(message, 'From');
@@ -36,11 +50,11 @@ export const parseGmailMessage = (message: gmail_v1.Schema$Message) => {
3650
historyId,
3751
internalDate,
3852
subject,
39-
from: rawFrom ? addressparser(rawFrom) : undefined,
40-
deliveredTo: rawDeliveredTo ? addressparser(rawDeliveredTo) : undefined,
41-
to: rawTo ? addressparser(rawTo) : undefined,
42-
cc: rawCc ? addressparser(rawCc) : undefined,
43-
bcc: rawBcc ? addressparser(rawBcc) : undefined,
53+
from: safeParseAddress(rawFrom),
54+
deliveredTo: safeParseAddress(rawDeliveredTo),
55+
to: safeParseAddress(rawTo),
56+
cc: safeParseAddress(rawCc),
57+
bcc: safeParseAddress(rawBcc),
4458
text,
4559
attachments,
4660
};
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,32 @@
11
export const sanitizeString = (str: string) => {
22
return str.replace(/\0/g, '');
33
};
4+
5+
/**
6+
* Sanitizes an email address to ensure it's in a valid format
7+
* - Removes null characters
8+
* - Normalizes Unicode characters
9+
* - Ensures proper encoding
10+
*/
11+
export const sanitizeEmailAddress = (email: string): string => {
12+
if (!email) return '';
13+
14+
// Remove null characters
15+
let sanitized = email.replace(/\0/g, '');
16+
17+
// Normalize Unicode characters
18+
sanitized = sanitized.normalize('NFKC');
19+
20+
// Remove any non-printable characters
21+
sanitized = sanitized.replace(/[\x00-\x1F\x7F-\x9F]/g, '');
22+
23+
// Ensure proper email format
24+
const parts = sanitized.split('@');
25+
if (parts.length !== 2) return sanitized;
26+
27+
// Sanitize local part and domain separately
28+
const localPart = parts[0].replace(/[^\w.!#$%&'*+/=?^`{|}~-]/g, '');
29+
const domain = parts[1].replace(/[^\w.-]/g, '');
30+
31+
return `${localPart}@${domain}`.toLowerCase();
32+
};
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import addressparser from 'addressparser';
22

33
import { Participant } from 'src/modules/messaging/message-import-manager/drivers/gmail/types/gmail-message.type';
4+
import { sanitizeEmailAddress } from 'src/modules/messaging/message-import-manager/drivers/gmail/utils/sanitize-string.util';
45

56
const formatAddressObjectAsArray = (
67
addressObject: addressparser.EmailAddress | addressparser.EmailAddress[],
@@ -12,6 +13,9 @@ const removeSpacesAndLowerCase = (email: string): string => {
1213
return email.replace(/\s/g, '').toLowerCase();
1314
};
1415

16+
/**
17+
* Formats an address object into participants with proper error handling and sanitization
18+
*/
1519
export const formatAddressObjectAsParticipants = (
1620
addressObject:
1721
| addressparser.EmailAddress
@@ -20,17 +24,38 @@ export const formatAddressObjectAsParticipants = (
2024
role: 'from' | 'to' | 'cc' | 'bcc',
2125
): Participant[] => {
2226
if (!addressObject) return [];
23-
const addressObjects = formatAddressObjectAsArray(addressObject);
27+
28+
try {
29+
const addressObjects = formatAddressObjectAsArray(addressObject);
2430

25-
const participants = addressObjects.map((addressObject) => {
26-
const address = addressObject.address;
31+
const participants = addressObjects.map((addressObject) => {
32+
const address = addressObject.address;
33+
34+
// Skip invalid addresses
35+
if (!address) {
36+
return null;
37+
}
2738

28-
return {
29-
role,
30-
handle: address ? removeSpacesAndLowerCase(address) : '',
31-
displayName: addressObject.name || '',
32-
};
33-
});
39+
// Sanitize the email address
40+
const sanitizedAddress = sanitizeEmailAddress(address);
41+
42+
// Skip if sanitization resulted in an invalid email
43+
if (!sanitizedAddress.includes('@')) {
44+
return null;
45+
}
3446

35-
return participants.flat();
47+
return {
48+
role,
49+
handle: removeSpacesAndLowerCase(sanitizedAddress),
50+
displayName: addressObject.name ? addressObject.name.normalize('NFKC') : '',
51+
};
52+
});
53+
54+
// Filter out any null entries from failed parsing
55+
return participants.filter((p): p is Participant => p !== null);
56+
} catch (error) {
57+
// Log the error but don't throw - return empty array instead
58+
console.error('Error formatting address object:', error);
59+
return [];
60+
}
3661
};

0 commit comments

Comments
 (0)