Merge pull request #25816 from barredterra/refactor-receive

refactor: receive email
This commit is contained in:
Akhil Narang 2024-04-12 12:23:46 +05:30 committed by GitHub
commit 245fbb6459
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -190,7 +190,7 @@ class EmailServer:
if cint(self.settings.use_imap):
self.check_imap_uidvalidity(folder)
readonly = False if self.settings.email_sync_rule == "UNSEEN" else True
readonly = self.settings.email_sync_rule != "UNSEEN"
self.imap.select(folder, readonly=readonly)
response, message = self.imap.uid("search", None, self.settings.email_sync_rule)
@ -213,27 +213,32 @@ class EmailServer:
if not uid_validity or uid_validity != current_uid_validity:
# uidvalidity changed & all email uids are reindexed by server
Communication = frappe.qb.DocType("Communication")
frappe.qb.update(Communication).set(Communication.uid, -1).where(
Communication.communication_medium == "Email"
).where(Communication.email_account == self.settings.email_account).run()
frappe.db.set_value(
"Communication",
{"communication_medium": "Email", "email_account": self.settings.email_account},
"uid",
-1,
update_modified=False,
)
if self.settings.use_imap:
# Remove {"} quotes that are added to handle spaces in IMAP Folder names
if folder[0] == folder[-1] == '"':
folder = folder[1:-1]
# new update for the IMAP Folder DocType
IMAPFolder = frappe.qb.DocType("IMAP Folder")
frappe.qb.update(IMAPFolder).set(IMAPFolder.uidvalidity, current_uid_validity).set(
IMAPFolder.uidnext, uidnext
).where(IMAPFolder.parent == self.settings.email_account_name).where(
IMAPFolder.folder_name == folder
).run()
frappe.db.set_value(
"IMAP Folder",
{"parent": self.settings.email_account_name, "folder_name": folder},
{"uidvalidity": current_uid_validity, "uidnext": uidnext},
update_modified=False,
)
else:
EmailAccount = frappe.qb.DocType("Email Account")
frappe.qb.update(EmailAccount).set(EmailAccount.uidvalidity, current_uid_validity).set(
EmailAccount.uidnext, uidnext
).where(EmailAccount.name == self.settings.email_account_name).run()
frappe.db.set_value(
"Email Account",
self.settings.email_account_name,
{"uidvalidity": current_uid_validity, "uidnext": uidnext},
update_modified=False,
)
sync_count = 100 if uid_validity else int(self.settings.initial_sync_count)
from_uid = 1 if uidnext < (sync_count + 1) or (uidnext - sync_count) < 1 else uidnext - sync_count
@ -245,10 +250,7 @@ class EmailServer:
pattern = rf"(?<={cmd} )[0-9]*"
match = re.search(pattern, response.decode("utf-8"), re.U | re.I)
if match:
return match.group(0)
else:
return None
return match[0] if match else None
def retrieve_message(self, uid, msg_num):
try:
@ -267,7 +269,7 @@ class EmailServer:
except Exception as e:
if self.has_login_limit_exceeded(e):
raise LoginLimitExceeded(e)
raise LoginLimitExceeded(e) from e
frappe.log_error("Unable to fetch email", self.make_error_msg(uid, msg_num))
@ -295,20 +297,18 @@ class EmailServer:
with suppress(Exception):
if not cint(self.settings.use_imap):
self.pop.dele(msg_num)
else:
# mark as seen if email sync rule is UNSEEN (syncing only unseen mails)
if self.settings.email_sync_rule == "UNSEEN":
self.imap.uid("STORE", uid, "+FLAGS", "(\\SEEN)")
elif self.settings.email_sync_rule == "UNSEEN":
self.imap.uid("STORE", uid, "+FLAGS", "(\\SEEN)")
def is_temporary_system_problem(self, e):
messages = (
"-ERR [SYS/TEMP] Temporary system problem. Please try again later.",
"Connection timed out",
)
for message in messages:
if message in strip(cstr(e)) or message in strip(cstr(getattr(e, "strerror", ""))):
return True
return False
return any(
message in strip(cstr(e)) or message in strip(cstr(getattr(e, "strerror", "")))
for message in messages
)
def make_error_msg(self, uid, msg_num):
traceback = frappe.get_traceback(with_context=True)
@ -322,14 +322,16 @@ class EmailServer:
partial_mail = Email(headers)
if partial_mail:
return (
"\nDate: {date}\nFrom: {from_email}\nSubject: {subject}\n\n\nTraceback: \n{traceback}".format(
date=partial_mail.date,
from_email=partial_mail.from_email,
subject=partial_mail.subject,
traceback=traceback,
)
)
return f"""
Date: {partial_mail.date}
From: {partial_mail.from_email}
Subject: {partial_mail.subject}
Traceback:
{traceback}
"""
return traceback
def update_flag(self, folder, uid_list=None):
@ -415,10 +417,7 @@ class Email:
# Convert non-string (e.g. None)
# Truncate to 140 chars (can be used as a document name)
self.subject = str(self.subject).strip()[:140]
if not self.subject:
self.subject = "No Subject"
self.subject = str(self.subject).strip()[:140] or "No Subject"
def set_from(self):
# gmail mailing-list compatibility
@ -499,12 +498,7 @@ class Email:
self.html_content += markdown(text_content)
def get_charset(self, part):
"""Detect charset."""
charset = part.get_content_charset()
if not charset:
charset = chardet.detect(safe_encode(cstr(part)))["encoding"]
return charset
return part.get_content_charset() or chardet.detect(safe_encode(cstr(part)))["encoding"]
def get_payload(self, part):
charset = self.get_charset(part)