Improve error-handling and error-reporting
1. Log the full traceback only once for each error (when we bounce the message). 2. Use 451 response code on processing failure. 3. Disable decoding message contents as we operate on raw data anyway.
This commit is contained in:
parent
0ef3012e33
commit
8955cf6c9d
2 changed files with 19 additions and 17 deletions
|
@ -40,7 +40,7 @@ class MailEncryptionProxy:
|
|||
message = email.message_from_bytes(envelope.original_content, policy=SMTPUTF8)
|
||||
|
||||
if message.defects:
|
||||
LOG.warning("Issues found: %d; %s", len(message.defects), repr(message.defects))
|
||||
LOG.warning("Issues found: %s", repr(message.defects))
|
||||
|
||||
send = xport.SendFrom(envelope.mail_from)
|
||||
for operation in gate.delivery_plan(envelope.rcpt_tos, message, keys):
|
||||
|
@ -48,14 +48,12 @@ class MailEncryptionProxy:
|
|||
try:
|
||||
new_message = operation.perform(message)
|
||||
send(new_message, operation.recipients())
|
||||
except (EncryptionException, MailSerialisationException, UnicodeEncodeError):
|
||||
# If the message can't be encrypted, deliver cleartext.
|
||||
LOG.exception('Unable to encrypt message, delivering in cleartext')
|
||||
if not isinstance(operation, KeepIntact):
|
||||
self._send_unencrypted(operation, envelope, send)
|
||||
else:
|
||||
LOG.exception('Cannot perform: %s', operation)
|
||||
raise
|
||||
except (EncryptionException, MailSerialisationException) as e:
|
||||
# If the message can't be encrypted or serialised to a
|
||||
# stream of bytes, deliver original payload in
|
||||
# cleartext.
|
||||
LOG.error('Unable to encrypt message, delivering in cleartext: %s', e)
|
||||
self._send_unencrypted(operation, envelope, send)
|
||||
|
||||
except:
|
||||
LOG.exception('Unexpected exception caught, bouncing message')
|
||||
|
@ -63,7 +61,7 @@ class MailEncryptionProxy:
|
|||
if conf.should_log_headers():
|
||||
LOG.error('Erroneous message headers: %s', self._beginning(envelope))
|
||||
|
||||
return xport.RESULT_ERROR
|
||||
return xport.RESULT_ABORT
|
||||
|
||||
return xport.RESULT_OK
|
||||
|
||||
|
@ -80,9 +78,6 @@ class MailEncryptionProxy:
|
|||
end = min(limit, 2560)
|
||||
return e.original_content[0:end]
|
||||
|
||||
def _seconds_between(self, start_ms, end_ms) -> float:
|
||||
return (end_ms - start_ms) * 1000
|
||||
|
||||
|
||||
def _init_controller(keys: kcache.KeyRing, max_body_bytes=None, tout: float = 5):
|
||||
proxy = MailEncryptionProxy(keys)
|
||||
|
@ -90,7 +85,10 @@ def _init_controller(keys: kcache.KeyRing, max_body_bytes=None, tout: float = 5)
|
|||
LOG.info(f"Initialising a mail Controller at {host}:{port}")
|
||||
return Controller(proxy, hostname=host, port=port,
|
||||
ready_timeout=tout,
|
||||
data_size_limit=max_body_bytes)
|
||||
data_size_limit=max_body_bytes,
|
||||
# Do not decode data into str as we only operate on raw
|
||||
# data available via Envelope.original_content.
|
||||
decode_data=False)
|
||||
|
||||
|
||||
def _validate_config():
|
||||
|
|
|
@ -9,8 +9,9 @@ import lacre.config as conf
|
|||
# Mail status constants.
|
||||
#
|
||||
# These are the only values that our mail handler is allowed to return.
|
||||
RESULT_OK = '250 OK'
|
||||
RESULT_ERROR = '500 Could not process your message'
|
||||
RESULT_OK = '250 OK' # delivered
|
||||
RESULT_ABORT = '451 Aborted: error in processing' # aborted, retry later
|
||||
RESULT_FAILED = '554 Transaction failed' # failed
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
@ -68,4 +69,7 @@ class SendFrom:
|
|||
if conf.flag_enabled('relay', 'starttls'):
|
||||
smtp.starttls()
|
||||
|
||||
smtp.sendmail(self._from_addr, recipients, message)
|
||||
try:
|
||||
smtp.sendmail(self._from_addr, recipients, message)
|
||||
except smtplib.SMTPException:
|
||||
LOG.exception('Failed to deliver message')
|
||||
|
|
Loading…
Reference in a new issue