Fix: When re-sending emails if they trigger exceptions move out of failed dir (#1411)
* Fix: When re-sending emails if they trigger exceptions move out of failed dir * Use proper timeout * Lint Co-authored-by: Adrià Casajús <adria.casajus@proton.ch>
This commit is contained in:
parent
25743da161
commit
4661972f97
|
@ -123,7 +123,9 @@ class MailSender:
|
||||||
smtp_port = config.POSTFIX_PORT
|
smtp_port = config.POSTFIX_PORT
|
||||||
try:
|
try:
|
||||||
start = time.time()
|
start = time.time()
|
||||||
with SMTP(config.POSTFIX_SERVER, smtp_port, config.POSTFIX_TIMEOUT) as smtp:
|
with SMTP(
|
||||||
|
config.POSTFIX_SERVER, smtp_port, timeout=config.POSTFIX_TIMEOUT
|
||||||
|
) as smtp:
|
||||||
if config.POSTFIX_SUBMISSION_TLS:
|
if config.POSTFIX_SUBMISSION_TLS:
|
||||||
smtp.starttls()
|
smtp.starttls()
|
||||||
|
|
||||||
|
@ -154,6 +156,7 @@ class MailSender:
|
||||||
newrelic.agent.record_custom_metric(
|
newrelic.agent.record_custom_metric(
|
||||||
"Custom/smtp_sending_time", time.time() - start
|
"Custom/smtp_sending_time", time.time() - start
|
||||||
)
|
)
|
||||||
|
return True
|
||||||
except (
|
except (
|
||||||
SMTPException,
|
SMTPException,
|
||||||
ConnectionRefusedError,
|
ConnectionRefusedError,
|
||||||
|
@ -184,6 +187,20 @@ class MailSender:
|
||||||
mail_sender = MailSender()
|
mail_sender = MailSender()
|
||||||
|
|
||||||
|
|
||||||
|
def save_request_to_failed_dir(exception_name: str, send_request: SendRequest):
|
||||||
|
file_name = f"{exception_name}-{int(time.time())}-{uuid.uuid4()}.{SendRequest.SAVE_EXTENSION}"
|
||||||
|
failed_file_dir = os.path.join(config.SAVE_UNSENT_DIR, "failed")
|
||||||
|
try:
|
||||||
|
os.makedirs(failed_file_dir)
|
||||||
|
except FileExistsError:
|
||||||
|
pass
|
||||||
|
file_path = os.path.join(failed_file_dir, file_name)
|
||||||
|
file_contents = send_request.to_bytes()
|
||||||
|
with open(file_path, "wb") as fd:
|
||||||
|
fd.write(file_contents)
|
||||||
|
return file_path
|
||||||
|
|
||||||
|
|
||||||
def load_unsent_mails_from_fs_and_resend():
|
def load_unsent_mails_from_fs_and_resend():
|
||||||
if not config.SAVE_UNSENT_DIR:
|
if not config.SAVE_UNSENT_DIR:
|
||||||
return
|
return
|
||||||
|
@ -200,17 +217,31 @@ def load_unsent_mails_from_fs_and_resend():
|
||||||
try:
|
try:
|
||||||
send_request = SendRequest.load_from_file(full_file_path)
|
send_request = SendRequest.load_from_file(full_file_path)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
LOG.error(f"Could not load file {filename}: {e}")
|
LOG.e(f"Cannot load {filename}. Error {e}")
|
||||||
continue
|
continue
|
||||||
send_request.ignore_smtp_errors = True
|
try:
|
||||||
if mail_sender.send(send_request, 2):
|
send_request.ignore_smtp_errors = True
|
||||||
newrelic.agent.record_custom_event(
|
if mail_sender.send(send_request, 2):
|
||||||
"DeliverUnsentEmail", {"delivered": "true"}
|
os.unlink(full_file_path)
|
||||||
)
|
newrelic.agent.record_custom_event(
|
||||||
|
"DeliverUnsentEmail", {"delivered": "true"}
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
newrelic.agent.record_custom_event(
|
||||||
|
"DeliverUnsentEmail", {"delivered": "false"}
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
# Unlink original file to avoid re-doing the same
|
||||||
os.unlink(full_file_path)
|
os.unlink(full_file_path)
|
||||||
else:
|
LOG.e(
|
||||||
newrelic.agent.record_custom_event(
|
"email sending failed with error:%s "
|
||||||
"DeliverUnsentEmail", {"delivered": "false"}
|
"envelope %s -> %s, mail %s -> %s saved to %s",
|
||||||
|
e,
|
||||||
|
send_request.envelope_from,
|
||||||
|
send_request.envelope_to,
|
||||||
|
send_request.msg[headers.FROM],
|
||||||
|
send_request.msg[headers.TO],
|
||||||
|
save_request_to_failed_dir(e.__class__.__name__, send_request),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -114,7 +114,7 @@ def test_mail_sender_save_unsent_to_disk(server_fn):
|
||||||
with tempfile.TemporaryDirectory() as temp_dir:
|
with tempfile.TemporaryDirectory() as temp_dir:
|
||||||
config.SAVE_UNSENT_DIR = temp_dir
|
config.SAVE_UNSENT_DIR = temp_dir
|
||||||
send_request = create_dummy_send_request()
|
send_request = create_dummy_send_request()
|
||||||
mail_sender.send(send_request, 0)
|
assert not mail_sender.send(send_request, 0)
|
||||||
found_files = os.listdir(temp_dir)
|
found_files = os.listdir(temp_dir)
|
||||||
assert len(found_files) == 1
|
assert len(found_files) == 1
|
||||||
loaded_send_request = SendRequest.load_from_file(
|
loaded_send_request = SendRequest.load_from_file(
|
||||||
|
@ -135,7 +135,7 @@ def test_send_unsent_email_from_fs():
|
||||||
try:
|
try:
|
||||||
config.SAVE_UNSENT_DIR = temp_dir
|
config.SAVE_UNSENT_DIR = temp_dir
|
||||||
send_request = create_dummy_send_request()
|
send_request = create_dummy_send_request()
|
||||||
mail_sender.send(send_request, 1)
|
assert not mail_sender.send(send_request, 1)
|
||||||
finally:
|
finally:
|
||||||
config.POSTFIX_SERVER = original_postfix_server
|
config.POSTFIX_SERVER = original_postfix_server
|
||||||
config.NOT_SEND_EMAIL = True
|
config.NOT_SEND_EMAIL = True
|
||||||
|
@ -148,6 +148,8 @@ def test_send_unsent_email_from_fs():
|
||||||
compare_send_requests(send_request, sent_emails[0])
|
compare_send_requests(send_request, sent_emails[0])
|
||||||
assert sent_emails[0].ignore_smtp_errors
|
assert sent_emails[0].ignore_smtp_errors
|
||||||
assert not os.path.exists(os.path.join(config.SAVE_UNSENT_DIR, saved_files[0]))
|
assert not os.path.exists(os.path.join(config.SAVE_UNSENT_DIR, saved_files[0]))
|
||||||
|
saved_files = os.listdir(config.SAVE_UNSENT_DIR)
|
||||||
|
assert len(saved_files) == 0
|
||||||
|
|
||||||
|
|
||||||
@mail_sender.store_emails_test_decorator
|
@mail_sender.store_emails_test_decorator
|
||||||
|
@ -160,7 +162,7 @@ def test_failed_resend_does_not_delete_file():
|
||||||
config.SAVE_UNSENT_DIR = temp_dir
|
config.SAVE_UNSENT_DIR = temp_dir
|
||||||
send_request = create_dummy_send_request()
|
send_request = create_dummy_send_request()
|
||||||
# Send and store email in disk
|
# Send and store email in disk
|
||||||
mail_sender.send(send_request, 1)
|
assert not mail_sender.send(send_request, 1)
|
||||||
saved_files = os.listdir(config.SAVE_UNSENT_DIR)
|
saved_files = os.listdir(config.SAVE_UNSENT_DIR)
|
||||||
assert len(saved_files) == 1
|
assert len(saved_files) == 1
|
||||||
mail_sender.purge_stored_emails()
|
mail_sender.purge_stored_emails()
|
||||||
|
@ -176,3 +178,14 @@ def test_failed_resend_does_not_delete_file():
|
||||||
finally:
|
finally:
|
||||||
config.POSTFIX_SERVER = original_postfix_server
|
config.POSTFIX_SERVER = original_postfix_server
|
||||||
config.NOT_SEND_EMAIL = True
|
config.NOT_SEND_EMAIL = True
|
||||||
|
|
||||||
|
|
||||||
|
@mail_sender.store_emails_test_decorator
|
||||||
|
def test_ok_mail_does_not_generate_unsent_file():
|
||||||
|
with tempfile.TemporaryDirectory() as temp_dir:
|
||||||
|
config.SAVE_UNSENT_DIR = temp_dir
|
||||||
|
send_request = create_dummy_send_request()
|
||||||
|
# Send and store email in disk
|
||||||
|
assert mail_sender.send(send_request, 1)
|
||||||
|
saved_files = os.listdir(config.SAVE_UNSENT_DIR)
|
||||||
|
assert len(saved_files) == 0
|
||||||
|
|
Loading…
Reference in New Issue