summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuben Pollan <meskio@sindominio.net>2016-04-07 19:22:31 +0200
committerRuben Pollan <meskio@sindominio.net>2016-04-14 20:05:02 +0200
commitdb3b1369ce12efea2c3d06d0671bfa655ef49571 (patch)
tree6d94e0648c9d22334a597b7d66559e1273cbed89
parent8d45bc5b692801fc3df425d497a7210f84dae123 (diff)
[feature] Bounce stalled emails after a timeout.
* Resolves: #7998
-rw-r--r--README.md8
-rw-r--r--changes/next-changelog.txt2
-rw-r--r--src/leap/mx/mail_receiver.py34
3 files changed, 41 insertions, 3 deletions
diff --git a/README.md b/README.md
index d0b5018..c78b14b 100644
--- a/README.md
+++ b/README.md
@@ -33,6 +33,14 @@ $ python setup.py install
$ twistd -ny pkg/mx.tac
~~~
+### Stalled emails
+
+In case of problems with couchdb and other unknown sources emails can get
+stalled in the spool. There is a bouncing mechanism for long stalled emails,
+after 5 days the email will get bounced. The timestamp of stalled emails is
+hold in memory, restarting leap-mx will erase all timestamps and the stalled
+timeout will be reset.
+
## Hacking
Please see the doc/DESIGN docs.
diff --git a/changes/next-changelog.txt b/changes/next-changelog.txt
index f34adbd..65ed19c 100644
--- a/changes/next-changelog.txt
+++ b/changes/next-changelog.txt
@@ -12,6 +12,8 @@ Features
~~~~~~~~
- `#4285 <https://leap.se/code/issues/4285>`_: Add postfix lookup against couchdb for client smtp fingerprint
- `#5959 <https://leap.se/code/issues/5959>`_: Make alias resolver to return *uuid@deliver.local*
+- `#7998 <https://leap.se/code/issues/7998>`_: Bounce stalled emails after a timeout.
+
- `#1234 <https://leap.se/code/issues/1234>`_: Description of the new feature corresponding with issue #1234.
- New feature without related issue number.
diff --git a/src/leap/mx/mail_receiver.py b/src/leap/mx/mail_receiver.py
index 69079be..7c5a368 100644
--- a/src/leap/mx/mail_receiver.py
+++ b/src/leap/mx/mail_receiver.py
@@ -40,6 +40,7 @@ import signal
import json
import email.utils
+from datetime import datetime, timedelta
from email import message_from_string
from twisted.application.service import Service, IService
@@ -75,6 +76,11 @@ class MailReceiver(Service):
"""
RETRY_DIR_WATCH_DELAY = 60 * 5 # 5 minutes
+ """
+ Time delta to keep stalled emails
+ """
+ MAX_BOUNCE_DELTA = timedelta(days=5)
+
def __init__(self, users_cdb, directories, bounce_from,
bounce_subject):
"""
@@ -98,6 +104,7 @@ class MailReceiver(Service):
self._directories = directories
self._bounce_from = bounce_from
self._bounce_subject = bounce_subject
+ self._bounce_timestamp = {}
self._processing_skipped = False
def startService(self):
@@ -378,10 +385,31 @@ class MailReceiver(Service):
defer.returnValue(None)
log.msg("Encrypting message to %s's pubkey" % (uuid,))
- doc = yield self._encrypt_message(pubkey, mail_data)
+ try:
+ doc = yield self._encrypt_message(pubkey, mail_data)
+
+ yield self._export_message(uuid, doc)
+ yield self._remove(filepath)
+ except Exception as e:
+ yield self._bounce_with_timeout(filepath, msg, e)
+
+ @defer.inlineCallbacks
+ def _bounce_with_timeout(self, filepath, msg, error):
+ if filepath not in self._bounce_timestamp:
+ self._bounce_timestamp[filepath] = datetime.now()
+ log.msg("New stalled email {0!r}: {1!r}".format(filepath, error))
+ defer.returnValue(None)
- yield self._export_message(uuid, doc)
- yield self._remove(filepath)
+ current_delta = datetime.now() - self._bounce_timestamp[filepath]
+ if current_delta > self.MAX_BOUNCE_DELTA:
+ log.msg("Bouncing stalled email {0!r}: {1!r}"
+ .format(filepath, error))
+ bounce_reason = "There was a problem in the server and the " \
+ "email could not be delivered."
+ yield self._bounce_message(msg, filepath, bounce_reason)
+ else:
+ log.msg("Still stalled email {0!r} for the last {1}: {2!r}"
+ .format(filepath, str(current_delta), error))
@defer.inlineCallbacks
def _process_incoming_email(self, otherself, filepath, mask):