summaryrefslogtreecommitdiff
path: root/alot/mail
diff options
context:
space:
mode:
authorAnton Khirnov <anton@khirnov.net>2021-01-30 16:33:56 +0100
committerAnton Khirnov <anton@khirnov.net>2021-01-30 16:33:56 +0100
commit309fb25e9b089618c37f1a741fa6009cce54ac9e (patch)
tree2e9b65c7511a2bb6b726ab70a9e488dad74beef9 /alot/mail
parentcd35ec5f89cff3ba8c7780209efa7e8b0628744d (diff)
db/attachment: simplify the Attachment class
Make it a plain container around raw data and a few bits of metadata, rather than around a whole MIME part.
Diffstat (limited to 'alot/mail')
-rw-r--r--alot/mail/envelope.py109
1 files changed, 30 insertions, 79 deletions
diff --git a/alot/mail/envelope.py b/alot/mail/envelope.py
index 5a798f19..540c0342 100644
--- a/alot/mail/envelope.py
+++ b/alot/mail/envelope.py
@@ -7,12 +7,7 @@ import os
import re
import email
import email.policy
-from email.encoders import encode_7or8bit
from email.message import MIMEPart
-from email.mime.audio import MIMEAudio
-from email.mime.base import MIMEBase
-from email.mime.image import MIMEImage
-from email.mime.text import MIMEText
import email.charset as charset
from urllib.parse import unquote
@@ -85,57 +80,6 @@ def _guess_encoding(blob):
else:
raise Exception('Unknown magic API')
-# TODO: make this work on blobs, not paths
-def _mimewrap(path, filename, ctype):
- """Take the contents of the given path and wrap them into an email MIME
- part according to the content type. The content type is auto detected from
- the actual file contents and the file name if it is not given.
-
- :param path: the path to the file contents
- :type path: str
- :param filename: the file name to use in the generated MIME part
- :type filename: str or None
- :param ctype: the content type of the file contents in path
- :type ctype: str or None
- :returns: the message MIME part storing the data from path
- :rtype: subclasses of email.mime.base.MIMEBase
- """
-
- with open(path, 'rb') as f:
- content = f.read()
- if not ctype:
- ctype = helper.guess_mimetype(content)
- # libmagic < 5.12 incorrectly detects excel/powerpoint files as
- # 'application/msword' (see #179 and #186 in libmagic bugtracker)
- # This is a workaround, based on file extension, useful as long
- # as distributions still ship libmagic 5.11.
- if (ctype == 'application/msword' and
- not _libmagic_version_at_least(513)):
- mimetype, _ = mimetypes.guess_type(path)
- if mimetype:
- ctype = mimetype
-
- maintype, subtype = ctype.split('/', 1)
- if maintype == 'text':
- part = MIMEText(content.decode(_guess_encoding(content), 'replace'),
- _subtype=subtype,
- _charset='utf-8')
- elif maintype == 'image':
- part = MIMEImage(content, _subtype=subtype)
- elif maintype == 'audio':
- part = MIMEAudio(content, _subtype=subtype)
- else:
- part = MIMEBase(maintype, subtype)
- part.set_payload(content)
- # Encode the payload using Base64
- email.encoders.encode_base64(part)
- # Set the filename parameter
- if not filename:
- filename = os.path.basename(path)
- part.add_header('Content-Disposition', 'attachment',
- filename=filename)
- return part
-
class Envelope:
"""
a message that is not yet sent and still editable.
@@ -263,28 +207,37 @@ class Envelope:
if self.sent_time:
self.modified_since_sent = True
- def attach(self, attachment, filename=None, ctype=None):
+ def attach_file(self, path, filename = None):
+ with open(path, 'rb') as f:
+ data = f.read()
+
+ ctype = helper.guess_mimetype(data)
+ # libmagic < 5.12 incorrectly detects excel/powerpoint files as
+ # 'application/msword' (see #179 and #186 in libmagic bugtracker)
+ # This is a workaround, based on file extension, useful as long
+ # as distributions still ship libmagic 5.11.
+ if (ctype == 'application/msword' and
+ not _libmagic_version_at_least(513)):
+ mimetype, _ = mimetypes.guess_type(path)
+ if mimetype:
+ ctype = mimetype
+
+ # Set the filename parameter
+ if not filename:
+ filename = os.path.basename(path)
+
+ attachment = Attachment(data, ctype, filename, ())
+ self.attach(attachment)
+
+ def attach(self, attachment):
"""
attach a file
:param attachment: File to attach, given as
- :class:`~alot.db.attachment.Attachment` object or path to a file.
- :type attachment: :class:`~alot.db.attachment.Attachment` or str
- :param filename: filename to use in content-disposition.
- Will be ignored if `path` matches multiple files
- :param ctype: force content-type to be used for this attachment
- :type ctype: str
+ :class:`~alot.db.attachment.Attachment` object
+ :type attachment: :class:`~alot.db.attachment.Attachment`
"""
-
- if isinstance(attachment, Attachment):
- self.attachments.append(attachment)
- elif isinstance(attachment, str):
- path = os.path.expanduser(attachment)
- part = _mimewrap(path, filename, ctype)
- self.attachments.append(Attachment(part))
- else:
- raise TypeError('attach accepts an Attachment or str')
-
+ self.attachments.append(attachment)
if self.sent_time:
self.modified_since_sent = True
@@ -305,11 +258,9 @@ class Envelope:
# add attachments
for a in self.attachments:
- maintype, _, subtype = a.get_content_type().partition('/')
- fname = a.get_filename()
- data = a.get_data()
- mail.add_attachment(data, filename = fname,
- maintype = maintype, subtype = subtype)
+ mail.add_attachment(a.data, filename = a.filename,
+ maintype = a.content_maintype,
+ subtype = a.content_subtype)
if self.sign:
to_sign = mail
@@ -456,7 +407,7 @@ class Envelope:
if os.path.isfile(g)]
logging.debug('Attaching: %s', to_attach)
for path in to_attach:
- self.attach(path)
+ self.attach_file(path)
del self['Attach']
self.body = raw[headerEndPos:].strip()