Skip to content

Commit

Permalink
Do not fetch oversized emails from IMAP (#643)
Browse files Browse the repository at this point in the history
* Do not fetch oversized emails from IMAP

* Move constant

* move to try

* Rename constant
  • Loading branch information
squeaky-pl authored Jan 30, 2024
1 parent f7b0ad7 commit 206adc0
Show file tree
Hide file tree
Showing 4 changed files with 16 additions and 3 deletions.
1 change: 1 addition & 0 deletions inbox/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
MAX_MESSAGE_BODY_LENGTH = 100 * 1024 * 1024 # 100 MB
13 changes: 13 additions & 0 deletions inbox/crispin.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
import imapclient.imapclient
import imapclient.response_parser

from inbox.constants import MAX_MESSAGE_BODY_LENGTH

# Prevent "got more than 1000000 bytes" errors for servers that send more data.
imaplib._MAXLINE = 10000000 # type: ignore

Expand Down Expand Up @@ -877,6 +879,17 @@ def uids(self, uids: List[int]) -> List[RawMessage]:
# corrupt other UID data. Also we don't always get a message
# back at the first try.
for _ in range(3):
# We already reject parsing messages bigger than MAX_MESSAGE_BODY_PARSE_LENGTH.
# We might as well not download them at all, save bandwidth, processing time
# and prevent OOMs due to fetching oversized emails.
fetched_size: Dict[int, Dict[bytes, Any]] = self.conn.fetch(
uid, ["RFC822.SIZE"]
)
body_size = int(fetched_size.get(uid, {}).get(b"RFC822.SIZE", 0))
if body_size > MAX_MESSAGE_BODY_LENGTH:
log.warning("Skipping fetching of oversized message", uid=uid)
continue

result: Dict[int, Dict[bytes, Any]] = self.conn.fetch(
uid, ["BODY.PEEK[]", "INTERNALDATE", "FLAGS"]
)
Expand Down
1 change: 0 additions & 1 deletion inbox/models/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,3 @@
MAX_INDEXABLE_LENGTH = 191
MAX_FOLDER_NAME_LENGTH = MAX_INDEXABLE_LENGTH
MAX_LABEL_NAME_LENGTH = MAX_INDEXABLE_LENGTH
MAX_MESSAGE_BODY_PARSE_LENGTH = 100 * 1024 * 1024 # 100 MB
4 changes: 2 additions & 2 deletions inbox/models/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@
from sqlalchemy.sql.expression import false

from inbox.config import config
from inbox.constants import MAX_MESSAGE_BODY_LENGTH
from inbox.logging import get_logger
from inbox.models.account import Account
from inbox.models.base import MailSyncBase
from inbox.models.category import Category
from inbox.models.constants import MAX_MESSAGE_BODY_PARSE_LENGTH
from inbox.models.mixins import (
DeletedAtMixin,
HasPublicID,
Expand Down Expand Up @@ -318,7 +318,7 @@ def create_from_synced(

try:
body_length = len(body_string)
if body_length > MAX_MESSAGE_BODY_PARSE_LENGTH:
if body_length > MAX_MESSAGE_BODY_LENGTH:
raise MessageTooBigException(body_length)
parsed: MimePart = mime.from_string(body_string)
# Non-persisted instance attribute used by EAS.
Expand Down

0 comments on commit 206adc0

Please sign in to comment.