def make_report(spam_list, conf, mbox):
    datestr = datetime.now().strftime("%A, %d. %B %Y")
    spam_list = sorted(spam_list, key=lambda s: float(s.score))
    total_size = len(spam_list)
    pwd = os.path.dirname(os.path.realpath(__file__))
    logo = base64.b64encode(open(pwd + "/logo.png",
                                 "rb").read()).decode("utf-8")
    msg = email.mime.text.MIMEText(
        make_report_header(logo, datestr, total_size) +
        make_report_body(spam_list) + make_report_footer(), 'html', "utf-8")

    msg['From'] = "%s <%s>" % (conf.from_name, conf.from_address)
    msg['To'] = "%s <%s>" % (mbox, mbox)
    msg['Subject'] = "Quarantine Report for %s" % str(mbox)
    msg['Date'] = email.utils.formatdate(localtime=1)
    msg.policy = EmailPolicy()
    return msg
예제 #2
0
def update_mail_to_from(bytes_data, rcpttos, mailfrom):
    msg = message_from_bytes(bytes_data,
                             policy=EmailPolicy(utf8=True, linesep='\r\n'))

    logging.debug('Removing To: %s', msg['To'])
    del msg['To']
    msg['To'] = rcpttos
    logging.debug('Added To: %s', msg['To'])

    logging.debug('Removing From: %s', msg['From'])
    del msg['From']
    msg['From'] = mailfrom
    logging.debug('Added From: %s', msg['From'])

    mail_bytes = msg.as_bytes()
    logging.debug('update_mail_to_from got %i bytes and returned %i bytes',
                  len(bytes_data), len(mail_bytes))
    return mail_bytes
예제 #3
0
파일: mail.py 프로젝트: nlyubchich/Meowth
from flask import request, current_app
from html2text import html2text
from string import Template
from project.tasks.mail import celery_send_mail
from email.policy import EmailPolicy
from project.models import MailTemplate
import flask_mail

flask_mail.message_policy = EmailPolicy(linesep='\r\n', refold_source='none')


def get_message(title,
                recipients,
                body=None,
                html=None,
                attachment_name=None,
                attachment_type=None,
                attachment=None):
    msg = flask_mail.Message(title, recipients=recipients)
    if body:
        msg.body = body
    if html:
        msg.html = html
    if attachment:
        msg.attach(attachment_name, attachment_type, attachment.read())
    return msg


def get_message_from_form(form, vacancy_title):
    recipients = current_app.config["MAILS_TO_SEND"]
    kwargs = {
예제 #4
0
    log.debug("Got mistletoe")
except ImportError as e:  # pragma: no cover
    try:
        from commonmark import commonmark

        log.debug("Got commonmark")
    except ImportError:

        def commonmark(msg):
            return msg

        print("No commonmark/markdown library installed. Install mistletoe"
              " or commonmark")

__version__ = "2020.08.14"
POLICY = EmailPolicy(utf8=True)
CONFIG_PATH = Path("~/.wemailrc").expanduser()
_parser = BytesParser(_class=EmailMessage, policy=POLICY)
_header_parser = BytesHeaderParser(policy=POLICY)
DEFAULT_HEADERS = {"From": "", "To": "", "Subject": ""}
DISPLAY_HEADERS = ("From", "To", "CC", "Reply-to", "List-Id", "Date",
                   "Subject")
EmailTemplate = collections.namedtuple("EmailTemplate", "name,content")
LOCAL_TZ = datetime.now(timezone.utc).astimezone().tzinfo


class WEmailError(Exception):
    pass


class WEmailDeliveryError(WEmailError):
예제 #5
0
import os
import logging

from emlx.message import EmlxMessage

# For partial message reassembly
import email
from email.policy import EmailPolicy

# Just enough to get a regular message back out without
# significantly altering the message payload.
minimal_policy = EmailPolicy(linesep="\r\n", refold_source="none")
APPLE_MARKER = "X-Apple-Content-Length"


class AMMessageRef(object):
    mailbox = None
    msgid = 0
    partial = False

    def __repr__(self):
        return "<AMMessageRef msgid=%r partial=%r path=%s>" % (
            self.msgid, self.partial, self.msg_path)

    def __init__(self, mailbox, msgid, partial=False):
        self.mailbox = mailbox
        self.msgid = msgid
        self.partial = partial

    @property
    def msg_dir(self):
예제 #6
0
 def __init__(self, content):
     super().__init__()
     msg = message_from_bytes(content,
                              policy=EmailPolicy(utf8=True, linesep='\r\n'))
     self._msg = msg
     logging.info('Message with subject: %s', self['Subject'])
예제 #7
0
class EMail(IDs):
    """Create multipart E-Mails"""
    __slots__ = [
        'company_id', 'mfrom', 'sender', 'receivers', 'subject', 'headers',
        'content', 'charset', 'attachments', 'host', 'user', 'sender'
    ]
    TO = 0
    CC = 1
    BCC = 2

    @staticmethod
    def force_encoding(charset: str, encoding: str) -> None:
        """Enforce an ``encoding'' for a definied ``charset'' overwriting system default behaviour"""
        try:
            charset_encoding = {
                'quoted-printable': QP,
                'qp': QP,
                'base64': BASE64,
                'b64': BASE64
            }[encoding.lower()]
            add_charset(charset=charset.lower(),
                        header_enc=charset_encoding,
                        body_enc=charset_encoding)
        except KeyError as e:
            raise error(f'Invalid character set or encoding: {e}')

    @staticmethod
    def from_string(content: str) -> EmailMessage:
        return cast(
            EmailMessage,
            email.message_from_string(content, policy=email.policy.default))

    nofold_policy = EmailPolicy(refold_source='none')

    @staticmethod
    def as_string(msg: EmailMessage, unixfrom: bool) -> str:
        try:
            return msg.as_string(unixfrom)
        except Exception:
            try:
                return msg.as_string(unixfrom, policy=EMail.nofold_policy)
            except Exception:
                return msg.as_string(unixfrom, policy=compat32)

    class Content:
        """Stores one part of a multipart message"""
        __slots__ = ['content', 'charset', 'content_type', 'related']

        def __init__(self, content: str, charset: Optional[str],
                     content_type: Optional[str]) -> None:
            self.content = content
            self.charset = charset
            self.content_type = content_type
            self.related: List[EMail.Content] = []

        def set_message(self, msg: EmailMessage,
                        charset: Optional[str]) -> None:
            if self.content_type is not None:
                msg.set_type(self.content_type)
            msg.set_payload(
                self.content,
                self.charset if self.charset is not None else charset)

    class Attachment(Content):
        """Stores an attachemnt as part of a multipart message"""
        __slots__ = ['raw_content', 'filename']

        def __init__(self, raw_content: bytes, charset: Optional[str],
                     content_type: Optional[str],
                     filename: Optional[str]) -> None:
            super().__init__('', charset, content_type)
            self.raw_content = raw_content
            self.filename = filename

        def set_message(self, msg: EmailMessage,
                        charset: Optional[str]) -> None:
            content_type = self.content_type if self.content_type is not None else 'application/octet-stream'
            if self.filename:
                content_type += f'; name="{self.filename}"'
            if charset is not None:
                content_type += f'; charset="{charset}"'
            msg['Content-Type'] = content_type
            if self.charset is not None:
                #				msg['Content-Transfer-Encoding'] = '8bit'
                content = self.raw_content.decode(self.charset)
            else:
                msg['Content-Transfer-Encoding'] = 'base64'
                content = base64.encodestring(
                    self.raw_content).decode('us-ascii')
            if self.filename:
                msg['Content-Description'] = self.filename
                msg['Content-Location'] = self.filename
                msg['Content-ID'] = f'<{self.filename}>'
            msg.set_payload(content, self.charset)

    def __init__(self) -> None:
        super().__init__()
        self.company_id: Optional[int] = None
        self.mfrom: Optional[str] = None
        self.sender: Optional[str] = None
        self.receivers: List[Tuple[int, str]] = []
        self.subject: Optional[str] = None
        self.headers: List[str] = []
        self.content: List[EMail.Content] = []
        self.charset: Optional[str] = None
        self.attachments: List[EMail.Content] = []
        try:
            self.host = socket.getfqdn()
        except Exception:
            self.host = fqdn
        pw = self.get_user()
        self.user = pw.pw_name if pw is not None else user
        if self.user and self.host:
            self.mfrom = self.sender = f'{self.user}@{self.host}'

    def set_company_id(self, company_id: Optional[int]) -> None:
        """Set company_id, used when signing the message"""
        self.company_id = company_id

    def set_envelope(self, mfrom: str) -> None:
        """Set the envelope from address"""
        self.mfrom = mfrom

    set_mfrom = set_envelope

    def set_sender(self, sender: str) -> None:
        """Set the sender of for the mail"""
        self.sender = sender

    set_from = set_sender

    def add_receiver(self, recv: str) -> None:
        """Add a receiver for the mail"""
        self.receivers.append((self.TO, recv))

    add_to = add_receiver

    def add_cc(self, recv: str) -> None:
        """Add a carbon copy receiver for the mail"""
        self.receivers.append((self.CC, recv))

    def add_bcc(self, recv: str) -> None:
        """Add a blind carbon copy receiver for the mail"""
        self.receivers.append((self.BCC, recv))

    def reset_recipients(self) -> None:
        """Clears all receivers of the mail"""
        self.receivers.clear()

    def set_subject(self, subject: str) -> None:
        """Set the content of the subject header"""
        self.subject = subject

    def add_header(self, head: str) -> None:
        """Add a header"""
        self.headers.append(head)

    def reset_header(self) -> None:
        """Clears all definied header"""
        self.headers.clear()

    def add_content(self, content: str, charset: Optional[str],
                    content_type: str) -> EMail.Content:
        """Add ``content'' (str), store it using ``charset'' and mark it of type ``content_type''"""
        rc = self.Content(content, charset, content_type)
        self.content.append(rc)
        return rc

    def reset_content(self) -> None:
        """Clearts all parts of the multipart message"""
        self.content.clear()

    def set_text(self,
                 text: str,
                 charset: Optional[str] = None) -> EMail.Content:
        """Add a plain ``text'' variant for the mail using ``charset''"""
        return self.add_content(text, charset, 'text/plain')

    def set_html(self,
                 html: str,
                 charset: Optional[str] = None) -> EMail.Content:
        """Add a ``html'' variant for the mail using ``charset''"""
        return self.add_content(html, charset, 'text/html')

    def set_charset(self, charset: str) -> None:
        """Set global ``charset'' to be used for this mail"""
        self.charset = charset

    def __content_type(self, content_type: Optional[str],
                       filename: Optional[str],
                       default: Optional[str]) -> Optional[str]:
        if content_type is None and filename is not None:
            content_type = mimetypes.guess_type(filename)[0]
        if content_type is None:
            content_type = default
        return content_type

    def add_text_attachment(
            self,
            content: str,
            charset: Optional[str] = None,
            content_type: Optional[str] = None,
            filename: Optional[str] = None,
            related: Optional[EMail.Content] = None) -> EMail.Attachment:
        """Add a textual attachment"""
        if charset is None:
            charset = 'UTF-8'
        content_type = self.__content_type(content_type, filename,
                                           'text/plain')
        at = self.Attachment(content.encode(charset), charset, content_type,
                             filename)
        if related is not None:
            related.related.append(at)
        else:
            self.attachments.append(at)
        return at

    def add_binary_attachment(
            self,
            raw_content: bytes,
            content_type: Optional[str] = None,
            filename: Optional[str] = None,
            related: Optional[EMail.Content] = None) -> EMail.Attachment:
        """Add a binary attachment"""
        content_type = self.__content_type(content_type, filename,
                                           'application/octet-stream')
        at = self.Attachment(raw_content, None, content_type, filename)
        if related is not None:
            related.related.append(at)
        else:
            self.attachments.append(at)
        return at

    def add_excel_attachment(
            self,
            raw_content: bytes,
            filename: Optional[str],
            related: Optional[EMail.Content] = None) -> EMail.Attachment:
        """Add an excel sheet binary representation attachement"""
        return self.add_binary_attachment(
            raw_content,
            content_type='application/vnd.ms-excel',
            filename=filename,
            related=related)

    def reset_Attachment(self) -> None:
        """Clears all attachments"""
        self.attachments.clear()

    __name_pattern = re.compile('^([a-z][a-z0-9_-]*):', re.IGNORECASE)

    def __cleanup_header(self, head: str) -> Tuple[Optional[str], str]:
        head = head.replace('\r\n', '\n').rstrip('\n')
        mtch = self.__name_pattern.match(head)
        return (mtch.group(1).lower() if mtch else None, head)

    def __finalize_header(self) -> Tuple[List[str], str]:
        headers: List[str] = []
        avail_headers: Set[str] = set()
        for head in self.headers:
            (name, header) = self.__cleanup_header(head)
            if name is not None and not name.startswith(
                    'content-') and not name in ('mime-version', ):
                headers.append(header)
                avail_headers.add(name)
        if not 'from' in avail_headers and self.sender:
            headers.append(f'From: {self.sender}')
        for (hid, sid) in [('to', self.TO), ('cc', self.CC)]:
            if not hid in avail_headers:
                recvs = [_r[1] for _r in self.receivers if _r[0] == sid]
                if recvs:
                    headers.append('{name}: {receivers}'.format(
                        name=hid.capitalize(), receivers=', '.join(recvs)))
        if not 'subject' in avail_headers and self.subject:
            headers.append(f'Subject: {self.subject}')
        charset = self.charset if self.charset is not None else 'UTF-8'
        nheaders = []
        for header in headers:
            (name, value) = header.split(':', 1)
            try:
                value.encode('ascii')
            except UnicodeEncodeError:
                nheaders.append('{name}: {content}'.format(
                    name=name,
                    content=Header(value.strip(),
                                   charset).encode().replace('\n', ' ')))
            else:
                nheaders.append(header.replace('\n', ' '))
        return (nheaders, charset)

    def build_mail(self) -> str:
        """Build the multipart mail and return it as a string"""
        (headers, charset) = self.__finalize_header()
        root = EmailMessage()
        for header in headers:
            (name, value) = header.split(':', 1)
            root[name] = value.strip()
        msgs = []
        parts = []
        if len(self.content) == 1:
            if not self.attachments:
                parts.append((root, self.content[0]))
            else:
                msg = EmailMessage()
                msgs.append(msg)
                root.attach(msg)
                parts.append((msg, self.content[0]))
        else:
            if self.content:
                if self.attachments:
                    parent = EmailMessage()
                    msgs.append(parent)
                    root.attach(parent)
                else:
                    parent = root
                parent.set_type('multipart/alternative')
                for content in self.content:
                    msg = EmailMessage()
                    msgs.append(msg)
                    parts.append((msg, content))
                    if content.related:
                        base_message = EmailMessage()
                        msgs.append(base_message)
                        base_message.set_type('multipart/related')
                        base_message.attach(msg)
                        for related in content.related:
                            r = EmailMessage()
                            msgs.append(r)
                            parts.append((r, related))
                            base_message.attach(r)
                        parent.attach(base_message)
                    else:
                        parent.attach(msg)
        for (msg, content) in parts:
            content.set_message(msg, charset)
        if self.attachments:
            root.set_type('multipart/related')
            for attachment in self.attachments:
                at = EmailMessage()
                msgs.append(at)
                root.attach(at)
                attachment.set_message(at, None)
        for msg in msgs:
            del msg['MIME-Version']
        return self.sign(EMail.as_string(root, False) + '\n')

    def send_mail(self) -> Tuple[bool, int, str, str]:
        """Build and send the mail"""
        (status, returnCode, out, err) = (False, 0, None, None)
        mail = self.build_mail()
        mfrom: Optional[str]
        if self.mfrom is not None:
            mfrom = self.mfrom
        elif self.sender:
            mfrom = parseaddr(self.sender)[1]
        else:
            mfrom = None
        recvs = [parseaddr(_r[1])[1] for _r in self.receivers]
        sendmail = which('sendmail')
        if not sendmail:
            sendmail = '/usr/sbin/sendmail'
        cmd = [sendmail]
        if mfrom is not None:
            cmd += ['-f', mfrom]
        cmd += ['--'] + recvs
        pp = subprocess.Popen(cmd,
                              stdin=subprocess.PIPE,
                              stdout=subprocess.PIPE,
                              stderr=subprocess.PIPE,
                              text=True,
                              errors='backslashreplace')
        (out, err) = pp.communicate(mail)
        returnCode = pp.returncode
        if returnCode == 0:
            status = True
        return (status, returnCode, out, err)

    def sign(self, message: str) -> str:
        return message