示例#1
0
文件: imap.py 项目: kovrov/maily
 def getMoreConversations(self, serial, count):
     with self._store.writeLock as transaction:
         self.manager.updated.emit(serial, State.InProgress, "step 1")
         thrids = store.ConversationsDefaultDict(self._store.snapshot.conversations)
         while len(thrids.added) < count:
             n = count - len(thrids.added)
             for item in self._fetch_uids(n):
                 thrids[item['X-GM-THRID']].message_ids.append(item['UID'])
                 thrids[item['X-GM-THRID']].message_ids.sort()
                 n -= 1
             if n > 0:
                 break
         self.manager.updated.emit(serial, State.InProgress, "step 2")
         # TODO: sort thrids.added by date
         for i, thrid in enumerate(thrids.added):
             uids = self._search_thrid(thrid)
             for uid, raw_headers in self._fetch_headers((uids[0],uids[-1]), ('SUBJECT','FROM','DATE')):
                 headers = self.email_parser.parsestr(raw_headers)
                 message = transaction.messages[uid]
                 message.subject = unicode(make_header(decode_header(headers['subject']))).replace('\r\n ',' ')
                 message.sender = unicode(make_header(decode_header(headers['from'])))
                 message.timestamp = mktime_tz(parsedate_tz(headers['date']))
             transaction.thrids[thrid].message_ids = uids
             transaction.thrids[thrid].subject = transaction.messages[uids[0]].subject
             transaction.thrids[thrid].date = transaction.messages[uids[-1]].timestamp
             self.manager.progress.emit(serial, float(i+1) / len(thrids.added))
             transaction.commit(block=True)
         self.manager.updated.emit(serial, State.Successful, "done")
def get_data():
    mails = []
    # Create connection to MySQL db
    try:
        con = connections.connect_MySQLdb()
    except Exception as e:
        logger.error(str(e))
        raise Exception

    logger.info('Successful connection to MySQLdb')
    cur = con.cursor()
    # Get value sender from database
    try:
        cur.execute("SELECT mb_value FROM `mb_properties` WHERE mb_field='Sender'")
        sender = cur.fetchone()[0]
        cur.execute("SELECT mb_value FROM `mb_properties` WHERE mb_field='Attempts'")
        attempt = cur.fetchone()[0]
        # Get all necessary information from database
        cur.execute("""
                    SELECT mail_id,
                    mail_to,
                    mail_subject,
                    mail_body,
                    sender_marker
                    FROM mb_mail_buffer
                    WHERE mb_mail_buffer.attempt < %s
                    AND mb_mail_buffer.date_send is NULL
                    """ % attempt)
        rows = cur.fetchall()
    except Exception as e:
        logger.error(str(e))
        raise Exception

    logger.info('Information from database is obtained')
    # Create email from obtained information
    for row in rows:
        msg = MIMEMultipart('related')
        msg['Subject'] = make_header([(row[2], 'UTF-8')])
        msg['Date'] = formatdate(localtime=True)
        msg['Organization'] = make_header([('SAMSUNG', 'UTF-8')])
        msg['X-Mailer'] = make_header([('MailSender', 'UTF-8')])
        msg['Message-ID'] = make_msgid()
        msg['From'] = make_header([(sender, 'UTF-8')])
        msg['To'] = make_header([(row[1].strip(), 'UTF-8')])
        msg.preamble = "This is a multi-part message in MIME format."
        msg.epilogue = "End of message"
        partbody = MIMEText(row[3], '', 'UTF-8')
        msg.attach(partbody)
        # Create a list with tags mail_id, email object and sender_marker
        mails.append((row[0], msg))
    cur.close()
    con.close()
    if mails:
        logger.info('Created %s letters' % len(mails))
    return mails
def send_to_admin(notsendmsg):
    try:
        con = connections.connect_MySQLdb()
        cur = con.cursor()
        cur.execute("SELECT mb_value FROM `mb_properties` WHERE mb_field='Sender'")
        sender = cur.fetchone()[0]
        # Get SMTP server address and port from database
        cur.execute("SELECT mb_value FROM `mb_properties` WHERE mb_field = 'SMTP server'")
        server = cur.fetchone()[0]
        cur.execute("SELECT mb_value FROM `mb_properties` WHERE mb_field = 'SMTP port'")
        port = int(cur.fetchone()[0])
        # Get admin email address from database
        cur.execute("SELECT mb_value FROM `mb_properties` WHERE mb_field='Admin email'")
        admin = cur.fetchone()[0]
        cur.close()
        con.close()
    except Exception as e:
        logger.error(str(e))
        raise Exception

    # Create connection to SMTP server
    try:
        # ransfer function of the parameter 2 server, port
        serversmtp = connections.connect_SMTP()
    except Exception as e:
        logger.error(str(e))
        raise Exception
    logger.info('Connected\n')
    serversmtp.noop()

    for msg in notsendmsg:
        # Create email fo admin
        email = MIMEMultipart('related')
        email['Subject'] = make_header([('SRK DPIportal [Mail Sender] Impossible send email!', 'UTF-8')])
        email['Date'] = formatdate(localtime=True)
        email['Organization'] = make_header([('SAMSUNG', 'UTF-8')])
        email['X-Mailer'] = make_header([('MailSender', 'UTF-8')])
        email['Message-ID'] = make_msgid()
        email['From'] = make_header([(sender, 'UTF-8')])
        email['To'] = make_header([(admin, 'UTF-8')])
        email.preamble = "This is a multi-part message in MIME format."
        email.epilogue = "End of message"
        partbody = MIMEText('Impossible send email to ' + msg[0] + '\n' + 'Error:\n' + msg[1], '', 'UTF-8')
        email.attach(partbody)
        try:
            serversmtp.sendmail(str(email['From']),
                                str(email['To']).split('; '),
                                email.as_string())
            logger.info('Mail was send to %s' % admin)
        except Exception as e:
            logger.error(e)
            logger.info('Impossible send email to admin %s' % admin)

    serversmtp.quit()
示例#4
0
    def _set_info(self, msg):
        if self.charset == 'us-ascii':
            msg['Subject'] = self.Subject
            msg['From'] = self.From

        else:
            if isinstance(self.Subject, unicode):
                subject = self.Subject
            else:
                subject = unicode(self.Subject, self.charset)
            msg['Subject'] = str(make_header([(subject, self.charset)]))

            if isinstance(self.From, unicode):
                from_ = self.From
            else:
                from_ = unicode(self.From, self.charset)
            msg['From'] = str(make_header([(from_, self.charset)]))


        if isinstance(self.To, basestring):
            msg['To'] = self.To
        else:
            self.To = list(self.To)
            msg['To'] = ", ".join(self.To)

        if self.RTo:
            if isinstance(self.RTo, basestring):
                msg.add_header('reply-to', self.RTo)
            else:
                self.RTo = list(self.RTo)
                msg.add_header('reply-to', ", ".join(self.RTo))

        if self.CC:
            if isinstance(self.CC, basestring):
                msg['CC'] = self.CC
            else:
                self.CC = list(self.CC)
                msg['CC'] = ", ".join(self.CC)


        if self.BCC:
            if isinstance(self.BCC, basestring):
                msg['BCC'] = self.BCC
            else:
                self.BCC = list(self.BCC)
                msg['BCC'] = ", ".join(self.BCC)


        if self.Headers:
            for key, value in self.Headers.items():
                msg[key] = str(value).encode(self.charset)


        msg['Date'] = self.Date
示例#5
0
 def get(self, key):
     pdf = db.get(key)
     fname = u"Beeline %s %s.pdf" % (pdf.name, gen_date(pdf),)
     fname = str(make_header([(fname.encode("utf-8"), "utf-8")]))
     self.response.headers["Content-Type"] = "application/pdf; name=\"%s\"" % (fname,)
     self.response.headers["Content-Disposition"] = "filename=\"%s\"" % (fname,)
     self.response.out.write(pdf.blob)
示例#6
0
def parse_message(addresses, message):
    for what in ["from", "to"]:
        field = message[what]
        if not field:
            continue
        header = str(make_header(decode_header(field)))
        parse_header(addresses, header)
示例#7
0
def ch_oneline(headerstr):
    # Decode header string in one line and convert into single charset.
    # Return (string, cset) tuple as check for failure.
    try:
        d = decode_header(headerstr)
        # At this point, we should rstrip() every string because some
        # MUA deliberately add trailing spaces when composing return
        # message.
        d = [(s.rstrip(), c) for (s, c) in d]
        # Find all charsets in the original header.  We use 'utf-8' rather
        # than using the first charset (in mailman 2.1.x) if multiple
        # charsets are used.
        csets = []
        for (s, c) in d:
            if c and c not in csets:
                csets.append(c)
        if len(csets) == 0:
            cset = 'us-ascii'
        elif len(csets) == 1:
            cset = csets[0]
        else:
            cset = 'utf-8'
        h = make_header(d)
        ustr = unicode(h)
        oneline = ''.join(ustr.splitlines())
        return oneline.encode(cset, 'replace'), cset
    except (LookupError, UnicodeError, ValueError, HeaderParseError):
        # possibly charset problem. return with undecoded string in one line.
        return ''.join(headerstr.splitlines()), 'us-ascii'
示例#8
0
    def _set_info(self, msg):
        if hasattr(self.additional_headers, 'items'):
            for ahkey, value in self.additional_headers.items():
                msg.add_header(ahkey, value);

        if self.charset == 'us-ascii':
            msg['Subject'] = self.Subject
        else:
            subject = unicode(self.Subject, self.charset)
            msg['Subject'] = str(make_header([(subject, self.charset)]))

        msg['From'] = self.From

        if isinstance(self.To, basestring):
            msg['To'] = self.To
        else:
            self.To = list(self.To)
            msg['To'] = ", ".join(self.To)

        if self.CC:
            if isinstance(self.CC, basestring):
                msg['CC'] = self.CC
            else:
                self.CC = list(self.CC)
                msg['CC'] = ", ".join(self.CC)

        msg['Date'] = self.Date
示例#9
0
文件: string.py 项目: bksim/mailman
def oneline(s, cset='us-ascii', in_unicode=False):
    """Decode a header string in one line and convert into specified charset.

    :param s: The header string
    :type s: string
    :param cset: The character set (encoding) to use.
    :type cset: string
    :param in_unicode: Flag specifying whether to return the converted string
        as a unicode (True) or an 8-bit string (False, the default).
    :type in_unicode: bool
    :return: The decoded header string.  If an error occurs while converting
        the input string, return the string undecoded, as an 8-bit string.
    :rtype: string
    """
    try:
        h = make_header(decode_header(s))
        ustr = h.__unicode__()
        line = EMPTYSTRING.join(ustr.splitlines())
        if in_unicode:
            return line
        else:
            return line.encode(cset, 'replace')
    except (LookupError, UnicodeError, ValueError, HeaderParseError):
        # possibly charset problem. return with undecoded string in one line.
        return EMPTYSTRING.join(s.splitlines())
示例#10
0
文件: common.py 项目: snits/stgit
 def __decode_header(header):
     """Decode a qp-encoded e-mail header as per rfc2047"""
     try:
         words_enc = decode_header(header)
         hobj = make_header(words_enc)
     except Exception as ex:
         raise CmdException('header decoding error: %s' % str(ex))
     return text(hobj)
示例#11
0
    def __init__(self, fetched_email):
        self._source = fetched_email
        accepted_types = ["text/plain", "text/html"]
        parsed = email.message_from_string(fetched_email)
        self._msg = parsed
        try:
            self.To = decodeaddresses(parsed.get_all("To", []))
            self.From = decodeaddresses(parsed.get_all("From", []))
            self.Cc = decodeaddresses(parsed.get_all("Cc", []))
            self.timestamp = mktime_tz(parsedate_tz(parsed["date"]))
            self.Date = datetime.fromtimestamp(self.timestamp)
            self.Subject = make_header(decode_header(parsed["subject"]))
            self.Subject = unicode(self.Subject)
            self.body = {}
            self.filenames = []
            self._files = {}
        except:
            print self._source
            pass
        if parsed.is_multipart():
            counter = 1
            for part in parsed.walk():
                # multipart/* are just containers
                if part.get_content_maintype() == "multipart":
                    continue
                filename = part.get_filename()
                if not filename:
                    if part.get_content_type() in accepted_types:
                        if part.get_content_type() not in self.body:
                            self.body[part.get_content_type()] = []
                        self.body[part.get_content_type()].append(part.get_payload(decode=True))
                    else:
                        ext = mimetypes.guess_extension(part.get_content_type())
                        if not ext:
                            # Use a generic bag-of-bits extension
                            ext = ".bin"
                            filename = "part-%03d%s" % (counter, ext)
                        counter += 1
                if filename:
                    filename = unicode(make_header(decode_header(filename)))
                    self.filenames.append(filename)
                    self._files[filename] = part

        else:
            if parsed.get_content_type() in accepted_types:
                self.body = parsed.get_payload(decode=True)
示例#12
0
def decode_mime(m):
    """Substitute matching encoded_word with unicode equiv."""
    h = decode_header(clean_spaces(m))
    try:
        u = smart_text(make_header(h))
    except (LookupError, UnicodeDecodeError):
        return m.group(0)
    return u
示例#13
0
def oneline(s):
    """Inspired by mailman.utilities.string.oneline"""
    try:
        h = make_header(decode_header(s))
        ustr = h.__unicode__()
        return ''.join(ustr.splitlines())
    except (LookupError, UnicodeError, ValueError, HeaderParseError):
        return ''.join(s.splitlines())
示例#14
0
def decode_mime(m):
    """substitute matching encoded_word with unicode equiv.
    """
    h = decode_header(clean_spaces(m))
    try:
        u = unicode(make_header(h))
    except UnicodeDecodeError:
        return m.group(0)
    return u
示例#15
0
	def poll(self, host, mailbox, user, passwd, room, ssl=True):
		"""Poll an IMAP mailbox"""
		log.info("Polling {0}@{1}".format(user, host))

		if 'seen' not in self.shelf.keys():
			seen = []
		else:
			seen = self.shelf['seen']
		if ssl:
			M = imaplib.IMAP4_SSL(host)
		else:
			M = imaplib.IMAP4(host)

		log.debug("IMAP LOGIN")
		code,message = M.login(user, passwd)
		log.debug("{0}: {1}".format(code, message))

		log.debug("IMAP SELECT: {0}".format(mailbox))
		M.select(mailbox)
		log.debug("{0}: {1}".format(code, message))
		log.debug("IMAP SEARCH")
		if self._highest_uid is None:
			search = '(SENTSINCE {})'.format((datetime.datetime.now() + datetime.timedelta(weeks=-1)).strftime('%d-%b-%Y'))
		else:
			search = '(UID {}:*)'.format(self._highest_uid)
		typ, data = M.search(None, search)
		log.debug("{0}: {1}".format(typ, data))

		for num in data[0].split():
			typ, data = M.fetch(num, '(RFC822.HEADER)')
			raw_mail = data[0][1]
			# raw_message is a bytestring which must be decoded to make it usable
			mail = email.message_from_string(raw_mail.decode("utf-8", "ignore"))
			if mail.get('Message-ID') not in seen:
				log.debug("New message: {0}".format(mail.get('Message-ID')))
				seen.append(mail.get('Message-ID'))

				message = 'New email arrived'
				for hdrname in ['From','To','Cc','Subject']:
					value = mail.get(hdrname) or None
					if value:
						if PY2:
							pairs = decode_header(value)
							hdrvalue = ' '.join([ unicode(t[0], t[1] or 'ASCII') for t in pairs ])
							message += "\n\t{}: {}".format(hdrname, hdrvalue)
						else:
							hi = make_header(decode_header(value))
							message += "\n\t{}: {}".format(hdrname, str(hi))

				self.send(room, message, message_type='groupchat')
			else:
				log.debug("Seen message: {0}".format(mail.get('Message-ID')))
			self._highest_uid = num.decode('ascii')
		M.close()
		M.logout()
		self.shelf['seen'] = seen
		self.shelf.sync()
示例#16
0
def oneline(s):
    """Inspired by mailman.utilities.string.oneline"""
    try:
        h = make_header(decode_header(s))
        ustr = h.__unicode__()
        return ''.join(ustr.splitlines())
    except (LookupError, UnicodeError, ValueError, HeaderParseError):
        # possibly charset problem. return with undecoded string in one line.
        return ''.join(s.splitlines())
示例#17
0
文件: mail.py 项目: runyaga/ptah
    def set_headers(self, message):
        charset = str(self.context.charset)

        extra = list(self.context.get_headers())
        for key, val, encode in itertools.chain(self._headers.values(), extra):
            if encode:
                message[key] = make_header(((val, charset),))
            else:
                message[key] = val
示例#18
0
def decode_email(file):
  # Prepare result
  theMail = {
    'attachment_list': [],
    'body': '',
    # Place all the email header in the headers dictionary in theMail
    'headers': {}
  }
  # Get Message
  msg = email.message_from_string(file)
  # Back up original file
  theMail['__original__'] = file
  # Recode headers to UTF-8 if needed
  for key, value in msg.items():
    decoded_value_list = decode_header(value)
    unicode_value = make_header(decoded_value_list)
    new_value = unicode_value.__unicode__().encode('utf-8')
    theMail['headers'][key.lower()] = new_value
  # Filter mail addresses
  for header in ('resent-to', 'resent-from', 'resent-cc', 'resent-sender',
                 'to', 'from', 'cc', 'sender', 'reply-to'):
    header_field = theMail['headers'].get(header)
    if header_field:
        theMail['headers'][header] = parseaddr(header_field)[1]
  # Get attachments
  body_found = 0
  for part in msg.walk():
    content_type = part.get_content_type()
    file_name = part.get_filename()
    # multipart/* are just containers
    # XXX Check if data is None ?
    if content_type.startswith('multipart'):
      continue
    # message/rfc822 contains attached email message
    # next 'part' will be the message itself
    # so we ignore this one to avoid doubling
    elif content_type == 'message/rfc822':
      continue
    elif content_type in ("text/plain", "text/html"):
      charset = part.get_content_charset()
      payload = part.get_payload(decode=True)
      #LOG('CMFMailIn -> ',0,'charset: %s, payload: %s' % (charset,payload))
      if charset:
        payload = unicode(payload, charset).encode('utf-8')
      if body_found:
        # Keep the content type
        theMail['attachment_list'].append((file_name,
                                           content_type, payload))
      else:
        theMail['body'] = payload
        body_found = 1
    else:
      payload = part.get_payload(decode=True)
      # Keep the content type
      theMail['attachment_list'].append((file_name, content_type,
                                         payload))
  return theMail
示例#19
0
def decodeaddresses(addresslist):
    alist = []
    for realname, email_address in getaddresses(addresslist):
        dh = []
        for s, c in decode_header(realname):
            if c:
                c = c.replace("gb2312", "gb18030")
            dh.append((s, c))
        alist.append((unicode(make_header(dh)), email_address))
    return alist
示例#20
0
def format_email(e, list_name):
    subject = e['Subject']
    subject = re.sub(r"(=\?.*\?=)(?!$)", r"\1 ", subject)
    subject = str(make_header(decode_header(subject)))
    subject = subject.replace('['+list_name.capitalize()+'] ', '')

    # message = '{}: {} * {} * {}'.format(list_name, obfuscate_address(e['From']), subject, strip_reply_lines(e))
    message = '{}: {}: {}'.format(list_name, obfuscate_address(e['From']), subject)

    return truncate(message)
 def _write_headers(self, headers):
     if headers:
         for name in sorted(headers.keys()):
             value = headers[name]
             if isinstance(value, unicode):
                 value = str(header.make_header([(value, 'utf-8')]))
             self.fileobj.write(name)
             self.fileobj.write(': ')
             self.fileobj.write(value)
             self.fileobj.write(CRLF)
     self.fileobj.write(CRLF)
示例#22
0
    def _update_from_text(self):
        try:
            self._raw = make_header([(self._text, self._charset)]).encode()
            return
        except:
            pass

        try:
            self._raw = make_header([(self._text, "utf-8")]).encode()
            self._charset = "utf-8"
            return
        except:
            pass

        try:
            self._raw = make_header([(self._text.encode("utf-8", errors="ignore"), "utf-8")]).encode()
            self._charset = "utf-8"
            return
        except:
            raise
示例#23
0
 def _write_headers(self, headers):
     if headers:
         for name in sorted(headers.keys()):
             value = headers[name]
             if value.encode('ascii', 'ignore') != value.encode('utf-8'):
                 value = header.make_header([(value, 'utf-8')]).encode()
             self.fileobj.write(name.encode('utf-8'))
             self.fileobj.write(b': ')
             self.fileobj.write(value.encode('utf-8'))
             self.fileobj.write(CRLF)
     self.fileobj.write(CRLF)
示例#24
0
 def _set_info(self, msg):
     if self.charset == 'us-ascii':
         msg['Subject'] = self.Subject
     else:
         subject = str(self.Subject, self.charset)
         msg['Subject'] = str(make_header([(subject, self.charset)]))
     msg['From'] = self.From
     if isinstance(self.To, str):
         msg['To'] = self.To
     else:
         msg['To'] = ", ".join(self.To)
示例#25
0
 def masseges(self):
     msg = MIMEMultipart()
     msg['Message-ID'] = make_msgid()
     msg['Date'] = formatdate(localtime=True)
     msg['From'] = make_header([('{}'.format(self.from_text), 'UTF-8'), ('<' + self.from_email + '>', 'us-ascii')])
     msg['To'] = self.to
     msg['Subject'] = self.subject
     msg['User-Agent'] = 'Horde Application Framework 5'
     msg['Content-Disposition'] = "inline"
     msg['Content-Transfer-Encoding'] = "8bit"
     msg.attach(MIMEText(self.message_text, _subtype='html', _charset='utf-8'))
     return(msg)
示例#26
0
def mixed_charsets(subject, prefix, prefix_pattern, ws):
    list_charset = 'us-ascii'
    chunks = decode_header(subject.encode())
    if len(chunks) == 0:
        subject_text = '(no subject)'
        chunks = [(prefix, list_charset),
                  (subject_text, list_charset),
                  ]
        return make_header(chunks, continuation_ws=ws)
    # Only search the first chunk for Re and existing prefix.
    chunk_text, chunk_charset = chunks[0]
    if chunk_charset is None:
        chunk_charset = 'us-ascii'
    first_text = chunk_text.decode(chunk_charset)
    first_text = re.sub(prefix_pattern, '', first_text).lstrip()
    rematch = re.match(RE_PATTERN, first_text, re.I)
    if rematch:
        first_text = 'Re: ' + first_text[rematch.end():]
    chunks[0] = (first_text, chunk_charset)
    chunks.insert(0, (prefix, list_charset))
    return make_header(chunks, continuation_ws=ws)
示例#27
0
def process_stream_message(to: str, message: message.Message,
                           debug_info: Dict[str, Any]) -> None:
    subject_header = str(make_header(decode_header(message.get("Subject", ""))))
    subject = strip_from_subject(subject_header) or "(no topic)"

    stream, show_sender = extract_and_validate(to)
    # Don't remove quotations if message is forwarded:
    remove_quotations = not is_forwarded(subject_header)
    body = construct_zulip_body(message, stream.realm, show_sender, remove_quotations)
    debug_info["stream"] = stream
    send_zulip(settings.EMAIL_GATEWAY_BOT, stream, subject, body)
    logger.info("Successfully processed email to %s (%s)" % (
        stream.name, stream.realm.string_id))
示例#28
0
def send_email_simple(sender, receiver, subject, text, html, attachments=()):
    """
    send_email simple function
    """
    charset = "UTF-8"

    msg = MIMEMultipart('related')

    msg['From'] = str(make_header([(sender, charset)]))
    msg['To'] = str(make_header([(receiver, charset)]))
    msg['Subject'] = str(make_header([(subject, charset)]))
    msg['Date'] = formatdate()

    body = MIMEMultipart('alternative')
    plain_part = MIMEText(text, 'plain', charset)
    plain_part.add_header('Content-Disposition', 'inline')
    html_part = MIMEText(html, 'html', charset)
    html_part.add_header('Content-Disposition', 'inline')
    body.attach(plain_part)
    body.attach(html_part)

    msg.attach(body)

    for filename, cid in attachments:
        fp = open(filename, 'rb')
        img = MIMEImage(fp.read())
        fp.close()
        if cid:
            img.add_header('Content-ID', '<%s>' % cid)
            img.add_header('Content-Disposition', 'inline')
        else:
            img.add_header('Content-Disposition', 'attachment', filename=os.path.basename(filename))
        msg.attach(img)

    # Send the message via local SMTP server.
    s = smtplib.SMTP('localhost')
    s.sendmail(sender, receiver, msg.as_string())
    s.quit()
示例#29
0
文件: command.py 项目: aregee/Mailman
 def __init__(self, msg, msgdata, results):
     self.command_lines = []
     self.ignored_lines = []
     self.processed_lines = []
     # Depending on where the message was destined to, add some implicit
     # commands.  For example, if this was sent to the -join or -leave
     # addresses, it's the same as if 'join' or 'leave' commands were sent
     # to the -request address.
     subaddress = msgdata.get('subaddress')
     if subaddress == 'join':
         self.command_lines.append('join')
     elif subaddress == 'leave':
         self.command_lines.append('leave')
     elif subaddress == 'confirm':
         mo = re.match(config.mta.verp_confirm_regexp, msg.get('to', ''))
         if mo:
             self.command_lines.append('confirm ' + mo.group('cookie'))
     # Extract the subject header and do RFC 2047 decoding.
     raw_subject = msg.get('subject', '')
     try:
         subject = unicode(make_header(decode_header(raw_subject)))
         # Mail commands must be ASCII.
         self.command_lines.append(subject.encode('us-ascii'))
     except (HeaderParseError, UnicodeError, LookupError):
         # The Subject header was unparseable or not ASCII.  If the raw
         # subject is a unicode object, convert it to ASCII ignoring all
         # bogus characters.  Otherwise, there's nothing in the subject
         # that we can use.
         if isinstance(raw_subject, unicode):
             safe_subject = raw_subject.encode('us-ascii', 'ignore')
             self.command_lines.append(safe_subject)
     # Find the first text/plain part of the message.
     part = None
     for part in typed_subpart_iterator(msg, 'text', 'plain'):
         break
     if part is None or part is not msg:
         # Either there was no text/plain part or we ignored some
         # non-text/plain parts.
         print(_('Ignoring non-text/plain MIME parts'), file=results)
     if part is None:
         # There was no text/plain part to be found.
         return
     body = part.get_payload(decode=True)
     # text/plain parts better have string payloads.
     assert isinstance(body, basestring), 'Non-string decoded payload'
     lines = body.splitlines()
     # Use no more lines than specified
     max_lines = int(config.mailman.email_commands_max_lines)
     self.command_lines.extend(lines[:max_lines])
     self.ignored_lines.extend(lines[max_lines:])
示例#30
0
def mixed_charsets(mlist, msgdata, subject, prefix, prefix_pattern, ws):
    list_charset = mlist.preferred_language.charset
    chunks = decode_header(subject.encode())
    if len(chunks) == 0:
        with _.push(mlist.preferred_language.code):
            subject_text = _('(no subject)')
        chunks = [(prefix, list_charset),
                  (subject_text, list_charset),
                  ]
        return make_header(chunks, continuation_ws=ws)
    # Only search the first chunk for Re and existing prefix.
    chunk_text, chunk_charset = chunks[0]
    if chunk_charset is None:
        chunk_charset = 'us-ascii'
    first_text = chunk_text.decode(chunk_charset)
    first_text = re.sub(prefix_pattern, '', first_text).lstrip()
    rematch = re.match(RE_PATTERN, first_text, re.I)
    if rematch:
        first_text = 'Re: ' + first_text[rematch.end():]
    chunks[0] = (first_text, chunk_charset)
    # The subject text stripped of the prefix, for use in the NNTP gateway.
    msgdata['stripped_subject'] = str(make_header(chunks, continuation_ws=ws))
    chunks.insert(0, (prefix, list_charset))
    return make_header(chunks, continuation_ws=ws)
示例#31
0
def buildEmailMessage(from_url, to_url, msg=None,
                      subject=None, attachment_list=None,
                      extra_headers=None,
                      additional_headers=None):
  """
    Builds a mail message which is ready to be
    sent by Zope MailHost.

    * attachment_list is a list of dictionaries with those keys:
     - name : name of the attachment,
     - content: data of the attachment
     - mime_type: mime-type corresponding to the attachment
    * extra_headers is a dictionary of custom headers to add to the email.
      "X-" prefix is automatically added to those headers.
    * additional_headers is similar to extra_headers, but no prefix is added.
  """

  if attachment_list == None:
    # Create non multi-part MIME message.
    message = MIMEText(msg, _charset='utf-8')
    attachment_list = []
  else:
    # Create multi-part MIME message.
    message = MIMEMultipart()
    message.preamble = "If you can read this, your mailreader\n" \
                        "can not handle multi-part messages!\n"
    message.attach(MIMEText(msg, _charset='utf-8'))

  if extra_headers:
    for key, value in extra_headers.items():
      message.add_header('X-%s' % key, value)

  if additional_headers:
    for key, value in additional_headers.items():
      message.add_header(key, value)

  if subject:
    message.add_header('Subject',
                        make_header([(subject, 'utf-8')]).encode())
  if from_url:
    message.add_header('From', from_url)
  if to_url:
    message.add_header('To', to_url)

  for attachment in attachment_list:
    attachment_name = attachment.get('name', '')

    # try to guess the mime type
    if not attachment.has_key('mime_type'):
      mime_type, _ = guess_type( attachment_name )
      if mime_type is not None:
        attachment['mime_type'] = mime_type
      else:
        attachment['mime_type'] = 'application/octet-stream'

    # attach it
    if attachment['mime_type'] == 'text/plain':
      part = MIMEText(attachment['content'], _charset='utf-8')
    else:
      major, minor = attachment['mime_type'].split('/', 1)
      if major == 'text':
        part = MIMEText(attachment['content'], _subtype=minor)
      elif major == 'image':
        part = MIMEImage(attachment['content'], _subtype=minor)
      elif major == 'audio':
        part = MIMEAudio(attachment['content'], _subtype=minor)
      else:
        #  encode non-plaintext attachment in base64
        part = MIMEBase(major, minor)
        part.set_payload(attachment['content'])
        encoders.encode_base64(part)

    part.add_header('Content-Disposition', 'attachment',
                    filename=attachment_name)
    part.add_header('Content-ID', '<%s>' % \
                    ''.join(['%s' % ord(i) for i in attachment_name]))
    message.attach(part)

  return message
示例#32
0
def handle_header_content(content: str) -> str:
    """
    Deals with converting encoded headers to readable python string.
    """
    return str(make_header(decode_header(content)))
示例#33
0
    def share(self, msgfile):
        msg = email.message_from_file(msgfile)
        args = {}
        files = []

        check = getattr(settings, 'EMAIL2POST_CHECK', {})
        for lhs in check:
            v = six.text_type(make_header(decode_header(msg.get(lhs, ''))))
            if not check[lhs] in v:
                return 77  # EX_NOPERM

        if msg.is_multipart():
            for part in msg.walk():
                attach = False
                t = part.get_content_type()

                if t == 'text/plain':
                    if part.get_filename(None):
                        attach = True
                    else:
                        args['content'] = part.get_payload(decode=True)

                if attach or \
                   t.startswith ('image/') or \
                   t.startswith ('audio/') or \
                   t.startswith ('video/') or \
                   t.startswith('application/'):
                    payload = part.get_payload(decode=True)
                    os.umask(0)
                    tmp = TemporaryUploadedFile(
                        name=part.get_filename('attachment'),
                        content_type=t,
                        size=len(payload),
                        charset=None)
                    tmp.write(payload)
                    tmp.seek(0)
                    os.chmod(tmp.file.name, 0o644)
                    files.append(tmp)
        else:
            args['content'] = msg.get_payload(decode=True)

        subject = msg.get('Subject', None)
        if subject:
            hdr = make_header(decode_header(subject))
            args['title'] = six.text_type(hdr)

        # Mail subject may contain @foo, a selfposts' class name for which
        # this message is post to.
        m = re.search(r'(\A|\s)@(\w[\w\-]+)', args['title'])
        if m:
            cls = m.groups()[1]
            args['title'] = re.sub(r'(\A|\s)@(\w[\w\-]+)', '', args['title'])
            s = Service.objects.filter(cls=cls, api='selfposts').values('id')
            if len(s):
                args['id'] = s[0]['id']

        # Mail subject may contain "!draft" literal.
        if '!draft' in args['title']:
            args['title'] = args['title'].replace('!draft', '').strip()
            args['draft'] = True

        # Mail subject may contain "!friends-only" literal.
        if '!friends-only' in args['title']:
            args['title'] = args['title'].replace('!friends-only', '').strip()
            args['friends_only'] = True

        if len(files):
            args['files'] = MultiValueDict()
            args['files'].setlist('docs', files)

        selfposts.API(None).share(args)
        return 0  # EX_OK
示例#34
0
 def header_as_unicode(key):
     decoded = header.decode_header(parsed_mail[key])
     return str(header.make_header(decoded))
示例#35
0
文件: emlx.py 项目: mikez/emlx
def safe_decode_header(header):
    """Not every email is RFC-conform."""
    try:
        return make_header(decode_header(header))
    except Exception:
        return header
示例#36
0
 def get_subject_from_mail(mail):
     text = make_header(decode_header(mail.get("Subject")))
     return str(text)
示例#37
0
    def poll(self, host, mailbox, user, passwd, room, ssl=True):
        """Poll an IMAP mailbox"""
        log.info("Polling {0}@{1}".format(user, host))

        if 'seen' not in self.shelf.keys():
            seen = []
        else:
            seen = self.shelf['seen']
        if ssl:
            M = imaplib.IMAP4_SSL(host)
        else:
            M = imaplib.IMAP4(host)

        log.debug("IMAP LOGIN")
        code, message = M.login(user, passwd)
        log.debug("{0}: {1}".format(code, message))

        log.debug("IMAP SELECT: {0}".format(mailbox))
        M.select(mailbox)
        log.debug("{0}: {1}".format(code, message))
        log.debug("IMAP SEARCH")
        if self._highest_uid is None:
            search = '(SENTSINCE {})'.format(
                (datetime.datetime.now() +
                 datetime.timedelta(weeks=-1)).strftime('%d-%b-%Y'))
        else:
            search = '(UID {}:*)'.format(self._highest_uid)
        typ, data = M.search(None, search)
        log.debug("{0}: {1}".format(typ, data))

        for num in data[0].split():
            typ, data = M.fetch(num, '(RFC822.HEADER)')
            raw_mail = data[0][1]
            # raw_message is a bytestring which must be decoded to make it usable
            mail = email.message_from_string(raw_mail.decode(
                "utf-8", "ignore"))
            if mail.get('Message-ID') not in seen:
                log.debug("New message: {0}".format(mail.get('Message-ID')))
                seen.append(mail.get('Message-ID'))

                message = 'New email arrived'
                for hdrname in ['From', 'To', 'Cc', 'Subject']:
                    value = mail.get(hdrname) or None
                    if value:
                        if PY2:
                            pairs = decode_header(value)
                            hdrvalue = ' '.join([
                                unicode(t[0], t[1] or 'ASCII') for t in pairs
                            ])
                            message += "\n\t{}: {}".format(hdrname, hdrvalue)
                        else:
                            hi = make_header(decode_header(value))
                            message += "\n\t{}: {}".format(hdrname, str(hi))

                self.send(room, message, message_type='groupchat')
            else:
                log.debug("Seen message: {0}".format(mail.get('Message-ID')))
            self._highest_uid = num.decode('ascii')
        M.close()
        M.logout()
        self.shelf['seen'] = seen
        self.shelf.sync()
示例#38
0
def make_address(email, name=None):
    if name:
        return str(make_header(decode_header(formataddr((name, email)))))
    return email
示例#39
0
    def process_message(self, peer, mailfrom, rcpttos, data):
        message = email.message_from_string(data)

        from_str = message.get('From', "").strip()
        to_str = message.get('To', "").strip()
        cc_str = message.get('Cc', "").strip()
        subject = message.get('Subject', "").strip()
        try:
            subject = str(make_header(decode_header(subject)))
        except:
            pass
        command = subject.strip().lower()
        logging.info("Processing: from=%s|to=%s|cc=%s|subject=%s|", from_str,
                     to_str, cc_str, subject)

        _from = normalize([from_str])
        to = normalize(to_str.split(','))
        cc = normalize(cc_str.split(','))

        # Quick hack
        mailfrom = list(_from)[0]

        # Check cross-post
        mls = [_ for _ in (to | cc) if _.endswith(self.at_domain)]
        if len(mls) == 0:
            logging.error("No ML specified")
            return const.SMTP_STATUS_NO_ML_SPECIFIED
        elif len(mls) > 1:
            logging.error("Can't cross-post a message")
            return const.SMTP_STATUS_CANT_CROSS_POST

        # Aquire the ML name
        ml_address = mls[0]
        ml_name = ml_address.replace(self.at_domain, "")
        params = dict(ml_name=ml_name,
                      ml_address=ml_address,
                      mailfrom=mailfrom)

        # Remove the ML name from to'd and cc'd address lists
        if ml_address in to:
            to.remove(ml_address)
        if ml_address in cc:
            cc.remove(ml_address)

        # Is an error mail?
        if ml_name.endswith(ERROR_SUFFIX):
            ml_name = ml_name.replace(ERROR_SUFFIX, "")
            error_str = REMOVE_RFC822.sub(
                "", message.get('Original-Recipient', ""))
            error = normalize(error_str.split(','))
            if len(error) > 0 and len(ml_name) > 0:
                logging.error("not delivered to %s for %s", error, ml_name)
            return

        # Aquire current tenants
        tenants = db.find_tenants({"status": const.TENANT_STATUS_ENABLED})

        # Want a new ML?
        for config in tenants:
            if ml_name == config['new_ml_account']:
                tenant_name = config['tenant_name']
                ml_name = config['ml_name_format'] % \
                    db.increase_counter(config['tenant_name'])
                members = (to | cc | _from) - config['admins']
                db.create_ml(tenant_name, ml_name, subject, members, mailfrom)
                ml_address = ml_name + self.at_domain
                params = dict(ml_name=ml_name,
                              ml_address=ml_address,
                              mailfrom=mailfrom,
                              members=members)
                message = ensure_multipart(message, config['charset'])
                self.send_message(config, ml_name, message, mailfrom, params,
                                  config['welcome_msg'], 'Welcome.txt')
                return

        # Post a message to an existing ML

        # Check ML exists
        ml = db.get_ml(ml_name)
        if ml is None:
            logging.error("No such ML: %s", ml_name)
            return const.SMTP_STATUS_NO_SUCH_ML

        # Set config variable
        for config in tenants:
            if ml['tenant_name'] == config['new_ml_account']:
                break
        else:
            if config is None:
                logging.error("No such tenant: %s", ml['tenant_name'])
                return const.SMTP_STATUS_NO_SUCH_TENANT

        message = ensure_multipart(message, config['charset'])

        # Checking whether the sender is one of the ML members
        members = db.get_members(ml_name)
        if mailfrom not in (members | config['admins']):
            logging.error("Non-member post")
            return const.SMTP_STATUS_NOT_MEMBER

        # Update parameters
        new_ml_address = config['new_ml_account'] + self.at_domain
        params = dict(ml_name=ml_name,
                      ml_address=ml_address,
                      mailfrom=mailfrom,
                      new_ml_address=new_ml_address,
                      members=members)

        # Check ML status
        ml_status = ml['status']
        if ml_status == const.STATUS_CLOSED:
            if command == "reopen":
                self.send_message(config, ml_name, message, mailfrom, params,
                                  config['reopen_msg'], 'Reopen.txt')
                db.change_ml_status(ml_name, const.STATUS_OPEN, mailfrom)
                logging.info("reopened %s by %s", ml_name, mailfrom)
                return

            logging.error("ML is closed: %s", ml_name)
            return const.SMTP_STATUS_CLOSED_ML

        elif command == "close":
            self.send_message(config, ml_name, message, mailfrom, params,
                              config['goodbye_msg'], 'Goodbye.txt')
            db.change_ml_status(ml_name, const.STATUS_CLOSED, mailfrom)
            logging.info("closed %s by %s", ml_name, mailfrom)
            return

        if ml_status != const.STATUS_OPEN:
            db.change_ml_status(ml_name, const.STATUS_OPEN, mailfrom)

        # Remove admin members from cc
        cc -= config['admins']
        params["cc"] = cc

        # Remove cc'd members from the ML members if the subject is empty
        if command == "":
            if len(cc) > 0:
                params['members'] = members - cc
                self.send_message(config, ml_name, message, mailfrom, params,
                                  config['remove_msg'], 'RemoveMembers.txt')
                db.del_members(ml_name, cc, mailfrom)
                logging.info("removed %s from %s", cc, ml_name)
            return

        # Checking Cc:
        if len(cc) > 0:
            db.add_members(ml_name, cc, mailfrom)
            logging.info("added %s into %s", cc, ml_name)
            members = db.get_members(ml_name)
            params['members'] = members
            self.send_message(config, ml_name, message, mailfrom, params,
                              config['add_msg'], 'AddMembers.txt')
            return

        # Attach readme and send the post
        self.send_message(config, ml_name, message, mailfrom, params,
                          config['readme_msg'], 'Readme.txt')
示例#40
0
 def _decode_header(self, header_title: str) -> typing.Optional[str]:
     # FIXME : Handle exception
     if header_title in self._message:
         return str(make_header(decode_header(self._message[header_title])))
     else:
         return None
 def _get_file_name(self, input_str):
     try:
         return str(make_header(decode_header(input_str)))
     except Exception:
         return self._decode_uni_string(input_str, input_str)
示例#42
0
def sanitise_header(header_contents, header_name=None):
    """Clean and individual mail header.

    Given a header with header_contents, optionally labelled
    header_name, decode it with decode_header, sanitise it to make
    sure it decodes correctly and contains no invalid characters,
    then encode the result with make_header()
    """

    # We have some Py2/Py3 issues here.
    #
    # Firstly, the email parser (before we get here)
    # Python 3: headers with weird chars are email.header.Header
    #           class, others as str
    # Python 2: every header is an str
    #
    # Secondly, the behaviour of decode_header:
    # Python 3: weird headers are labelled as unknown-8bit
    # Python 2: weird headers are not labelled differently
    #
    # Lastly, aking matters worse, in Python2, unknown-8bit doesn't
    # seem to be supported as an input to make_header, so not only do
    # we have to detect dodgy headers, we have to fix them ourselves.
    #
    # We solve this by catching any Unicode errors, and then manually
    # handling any interesting headers.

    value = decode_header(header_contents)
    try:
        header = make_header(value,
                             header_name=header_name,
                             continuation_ws='\t')
    except UnicodeDecodeError:
        # At least one of the parts cannot be encoded as ascii.
        # Find out which one and fix it somehow.
        #
        # We get here under Py2 when there's non-7-bit chars in header,
        # or under Py2 or Py3 where decoding with the coding hint fails.

        new_value = []

        for (part, coding) in value:
            # We have random bytes that aren't properly coded.
            # If we had a coding hint, it failed to help.
            if six.PY3:
                # python3 - force coding to unknown-8bit
                new_value += [(part, 'unknown-8bit')]
            else:
                # python2 - no support in make_header for unknown-8bit
                # We should do unknown-8bit coding ourselves.
                # For now, we're just going to replace any dubious
                # chars with ?.
                #
                # TODO: replace it with a proper QP unknown-8bit codec.
                new_value += [
                    (part.decode('ascii',
                                 errors='replace').encode('ascii',
                                                          errors='replace'),
                     None)
                ]

        header = make_header(new_value,
                             header_name=header_name,
                             continuation_ws='\t')

    return header
示例#43
0
    # Walk the email and pull out all relevant information depending on the subject
    if 'User Submission:' in email_subject:
        for part in raw.walk():
            if part.get_content_type() == 'message/rfc822':
                part_string = str(part)
                #print(part_string) # Easy way to see the full message for this part if you need to

                try:
                    # Pulling the full email header of the attachment and then decoding it so I can truly get the to, from, and subject without formatting issues
                    # I had to pull a lot larger section because the email header format/order varied on me
                    attachment_header = re.search(
                        '(Content-Disposition:\sattachment;(.*?(\n))+.*?)MIME-Version:',
                        part_string)
                    coded_header = attachment_header.group(1)
                    decoded_header = make_header(decode_header(coded_header))
                    #print(decoded_header)

                    original_from = re.search('\sFrom:\s(.+?)\n?(\S+:)',
                                              str(decoded_header))
                    original_to = re.search('\sTo:\s(.+?)\n?(\S+:)',
                                            str(decoded_header))
                    original_subject = re.search(
                        'Subject:\s(.+?)\n?(\w+\-\w+:|From:\s|To:\s|Type:\s|Date:\s|References:\s)',
                        str(decoded_header))

                    from_address = original_from.group(1)
                    to_address = original_to.group(1)
                    email_subject = original_subject.group(1)

                # I need to clean this up. Right now if one fails, they all fail
示例#44
0
 def _convert(self, text):
     decoded = decode_header(text)
     if not decoded[0][1] or 'unknown' in decoded[0][1]:
         decoded = [(decoded[0][0], 'latin-1')]
     return str(make_header(decoded))
示例#45
0
def mbox_df(infile):
    try:
        row = []
        for message in mbox(infile):
            content = get_content(message)
            line = [str(parsedate_to_datetime(message['date'])), message['Message-ID'], message['In-Reply-To'], message['References'], message['from'], message['to'], message['Cc'], str(make_header(decode_header(message['subject']))), content]
            row.append(line)
    except Exception as e:
        print("Something wrong with your mbox file: ", infile, ". Check the file(s) if it is formed correctly. Maybe 'From ' in the mail body has not been correctly escaped as '>From '. Refer to the following resource:\nhttps://pymotw.com/3/mailbox/\nThe specific error message from Python: ", e, sep="")
    finally:
        df = DataFrame(row, columns=['date', 'message_ID', 'in_reply_to', 'references', 'from', 'to', 'cc', 'subject', 'content'])
        return df
示例#46
0
def get_formatted_email(user, mail=None):
    """get Email Address of user formatted as: `John Doe <*****@*****.**>`"""
    fullname = get_fullname(user)
    if not mail:
        mail = get_email_address(user)
    return cstr(make_header(decode_header(formataddr((fullname, mail)))))
示例#47
0
def downloaAttachmentsInEmail(m, emailid, outputdir):
    resp, data = m.fetch(emailid, '(RFC822)')
    email_body = data[0][1]
    mail = email.message_from_bytes(email_body)

    # Extract sender name and sender email address from the email
    sender = str(make_header(decode_header(mail['From'])))

    try:
        name, email_addr = sender.split('<')
        email_addr = email_addr.replace(">", "")
    except:
        print("Sender ohne Name")
        email_addr = sender
        name = " "

    if mail.get_content_maintype() != 'multipart':
        return -1

    # Each email address gets its own folder
    new_folder_name = "".join(email_addr.split("@")[0].split("."))

    outputdir = outputdir + new_folder_name + "/"
    if not os.path.exists(outputdir):
        os.makedirs(outputdir)

    for part in mail.walk():
        if part.get_content_maintype() != 'multipart' and part.get(
                'Content-Disposition') is not None:
            old_filename = part.get_filename()
            # Check if attachement contains "whatsapp chat"
            #if "whatsapp chat" not in old_filename.lower():
            #    return -1
            # Write file/attachment to disk
            if part.get_filename() is not None:
                sv_path = os.path.join(outputdir, old_filename)
                if not os.path.isfile(sv_path):
                    fp = open(sv_path, 'wb')
                    fp.write(part.get_payload(decode=True))
                    fp.close()

            # iOS: File is zipped; Android: File is a unzipped
            if ".txt" in old_filename:
                # File is from Android client
                # New Filename: DD_MM_YY_OLDFILENAME.txt
                new_filename = str((time.strftime("%d_%m_%Y"))) + "_" + \
                               old_filename
                os.rename(outputdir + old_filename, outputdir + new_filename)

            else:
                # File is from iOS client
                # New Filename: DD_MM_YY_OLDFILENAME.txt
                try:
                    new_filename = old_filename[:-3] + "txt"
                    unzip(outputdir + old_filename, outputdir)
                    os.rename(outputdir + '_chat.txt',
                              outputdir + new_filename)
                    os.remove(outputdir + old_filename)  # remove zip file

                except:
                    return -1

            return (new_folder_name, name, email_addr,
                    outputdir + new_filename)
示例#48
0
 def subject(self):
     """Message subject"""
     value = self.get("subject")
     return str(make_header(decode_header(value))) if value else None
示例#49
0
msg_list = []  # 取得したMIMEメッセージを格納するリスト
for num in datas[len(datas) - fetch_num::]:
    typ, data = imapclient.fetch(num, '(RFC822)')
    msg = email.message_from_bytes(data[0][1])
    msg_list.append(msg)
imapclient.close()
imapclient.logout()

os.system('cls')
c = 0
for msg in msg_list:
    print(msg)

for msg in msg_list:
    # 各ヘッダ情報はディクショナリのようにアクセスできる
    from_addr = str(make_header(decode_header(msg["From"])))
    subject = str(make_header(decode_header(msg["Subject"])))

    # 本文(payload)を取得する
    if msg.is_multipart() is False:
        # シングルパートのとき
        payload = msg.get_payload(decode=True)  # 備考の※1
        charset = msg.get_content_charset()  # 備考の※2
        if charset is not None:
            payload = payload.decode(charset, "ignore")
        print(payload)
        print()
    else:
        # マルチパートのとき
        for part in msg.walk():
            payload = part.get_payload(decode=True)
示例#50
0
def sanitise_header(header_contents, header_name=None):
    """Clean and individual mail header.

    Given a header with header_contents, optionally labelled
    header_name, decode it with decode_header, sanitise it to make
    sure it decodes correctly and contains no invalid characters,
    then encode the result with make_header()
    """

    try:
        value = decode_header(header_contents)
    except HeaderParseError:
        # something has gone really wrong with header parsing.
        # (e.g. base64 decoding) We probably can't recover, so:
        return None

    # We have some issues here.
    #
    # Firstly, in the email parser (before we get here) headers with weird
    # chars are email.header.Header class, others as str
    #
    # Secondly, the behaviour of decode_header: weird headers are labelled
    # as unknown-8bit
    #
    # We solve this by catching any Unicode errors, and then manually
    # handling any interesting headers.

    try:
        header = make_header(value,
                             header_name=header_name,
                             continuation_ws='\t')
    except (UnicodeDecodeError, LookupError, ValueError):
        #  - a part cannot be encoded as ascii. (UnicodeDecodeError), or
        #  - we don't have a codec matching the hint (LookupError)
        #  - the codec has a null byte (ValueError)
        # Find out which part and fix it somehow.
        #
        # We get here under where decoding with the coding hint fails.

        new_value = []

        for (part, _) in value:
            # We have random bytes that aren't properly coded.
            # If we had a coding hint, it failed to help.

            # python3 - force coding to unknown-8bit
            new_value += [(part, 'unknown-8bit')]

        header = make_header(new_value,
                             header_name=header_name,
                             continuation_ws='\t')

    try:
        header.encode()
    except (HeaderParseError, IndexError):
        # despite our best efforts, the header is stuffed
        # HeaderParseError: some very weird multi-line headers
        # IndexError: bug, thrown by make_header(decode_header(' ')).encode()
        return None

    return header
示例#51
0
def properly_decode_header(subject):
    contents = make_header(decode_header(subject))
    return str(contents)
    def handle(self, *args, **options):
        ##########
        # 1. Save the email-attachment file to the django model (database)
        ##########
        sticker_email_host = env('STICKER_EMAIL_HOST', '')
        sticker_email_port = env('STICKER_EMAIL_PORT', '')
        sticker_email_username = env('STICKER_EMAIL_USERNAME', '')
        sticker_email_password = env('STICKER_EMAIL_PASSWORD', '')

        if not sticker_email_host or not sticker_email_port or not sticker_email_username or not sticker_email_password:
            raise Exception(
                'Configure email settings at .env to process sticker responses'
            )

        context = ssl.create_default_context()
        imapclient = imaplib.IMAP4_SSL(sticker_email_host,
                                       sticker_email_port,
                                       ssl_context=context)

        # login
        imapclient.login(sticker_email_username, sticker_email_password)
        """
        Retrieve messages
        """
        imapclient.select('INBOX')  # Select mail box
        typ, data = imapclient.search(None, "ALL")  # data = [b"1 2 3 4 ..."]
        datas = data[0].split()
        fetch_num = 5000  # The number of messages to fetch

        if (len(datas) - fetch_num) < 0:
            fetch_num = len(datas)

        # msg_list = []

        for num in datas[len(datas) - fetch_num::]:
            try:
                ##########
                # 2. Save the attached files into the database
                ##########
                typ, data = imapclient.fetch(num, '(RFC822)')
                # typ, data = imapclient.fetch(num, '(BODY[HEADER.FIELDS (MESSAGE-ID)])')
                raw_email = data[0][1]

                # converts byte literal to string removing b''
                raw_email_string = raw_email.decode('utf-8')
                email_message = email.message_from_string(raw_email_string)

                email_message_id = str(
                    make_header(decode_header(email_message["Message-ID"])))
                if StickerPrintingResponseEmail.objects.filter(
                        email_message_id=email_message_id):
                    # This email has been saved in the database already.  Skip this email
                    continue

                email_subject = str(
                    make_header(decode_header(email_message["Subject"])))
                email_from = email_message['From']
                body = get_text(email_message)
                email_body = body.decode()
                email_date = email_message['Date']

                sticker_printing_response_email = StickerPrintingResponseEmail.objects.create(
                    email_subject=email_subject,
                    email_from=email_from,
                    email_body=email_body,
                    email_date=email_date,
                    email_message_id=email_message_id,
                )

                # downloading attachments
                for part in email_message.walk():
                    try:
                        # this part comes from the snipped I don't understand yet...
                        if part.get_content_maintype() == 'multipart':
                            continue
                        if part.get('Content-Disposition') is None:
                            continue
                        fileName = part.get_filename()
                        if bool(fileName) and fileName.lower().endswith(
                                '.xlsx'):
                            now = timezone.localtime(timezone.now())

                            # Create sticker_printing_response object. File is not saved yet
                            sticker_printing_response = StickerPrintingResponse.objects.create(
                                sticker_printing_response_email=
                                sticker_printing_response_email,
                                name=fileName,
                            )

                            # Load attachment file
                            my_bytes = part.get_payload(decode=True)
                            content_file = ContentFile(my_bytes)

                            # Save file
                            sticker_printing_response._file.save(
                                fileName, content_file)
                    except Exception as e:
                        logger.exception(
                            'Exception has been raised when importing .xlsx file'
                        )
                        continue

                # imapclient.store(num, "+FLAGS", "\\Deleted")
                imapclient.copy(num, "Archive")
                imapclient.store(num, "+FLAGS", "\\Deleted")
            except:
                logger.exception(
                    'Exception has been raised when processing emails')
                continue

        imapclient.close()
        imapclient.logout()

        ##########
        # 3. Process xlsx file saved in django model
        ##########
        updates, errors = process_sticker_printing_response()

        cmd_name = __name__.split('.')[-1].replace('_', ' ').upper()
        # error_count = len(errors) + len(error_filenames)
        error_count = len(errors)
        err_str = '<strong style="color: red;">Errors: {}</strong>'.format(
            error_count
        ) if error_count else '<strong style="color: green;">Errors: 0</strong>'
        msg = '<p>{} completed. {}. IDs updated: {}.</p>'.format(
            cmd_name, err_str, updates)
        logger.info(msg)
        print(
            msg)  # will redirect to cron_tasks.log file, by the parent script
示例#53
0
def sanitise_header(header_contents, header_name=None):
    """Clean and individual mail header.

    Given a header with header_contents, optionally labelled
    header_name, decode it with decode_header, sanitise it to make
    sure it decodes correctly and contains no invalid characters,
    then encode the result with make_header()
    """

    try:
        value = decode_header(header_contents)
    except HeaderParseError:
        # something has gone really wrong with header parsing.
        # (e.g. base64 decoding) We probably can't recover, so:
        return None

    # We have some Py2/Py3 issues here.
    #
    # Firstly, the email parser (before we get here)
    # Python 3: headers with weird chars are email.header.Header
    #           class, others as str
    # Python 2: every header is an str
    #
    # Secondly, the behaviour of decode_header:
    # Python 3: weird headers are labelled as unknown-8bit
    # Python 2: weird headers are not labelled differently
    #
    # Lastly, aking matters worse, in Python2, unknown-8bit doesn't
    # seem to be supported as an input to make_header, so not only do
    # we have to detect dodgy headers, we have to fix them ourselves.
    #
    # We solve this by catching any Unicode errors, and then manually
    # handling any interesting headers.

    try:
        header = make_header(value,
                             header_name=header_name,
                             continuation_ws='\t')
    except (UnicodeDecodeError, LookupError, ValueError, TypeError):
        #  - a part cannot be encoded as ascii. (UnicodeDecodeError), or
        #  - we don't have a codec matching the hint (LookupError)
        #  - the codec has a null byte (Py3 ValueError/Py2 TypeError)
        # Find out which part and fix it somehow.
        #
        # We get here under Py2 when there's non-7-bit chars in header,
        # or under Py2 or Py3 where decoding with the coding hint fails.

        new_value = []

        for (part, coding) in value:
            # We have random bytes that aren't properly coded.
            # If we had a coding hint, it failed to help.
            if six.PY3:
                # python3 - force coding to unknown-8bit
                new_value += [(part, 'unknown-8bit')]
            else:
                # python2 - no support in make_header for unknown-8bit
                # We should do unknown-8bit coding ourselves.
                # For now, we're just going to replace any dubious
                # chars with ?.
                #
                # TODO: replace it with a proper QP unknown-8bit codec.
                new_value += [
                    (part.decode('ascii',
                                 errors='replace').encode('ascii',
                                                          errors='replace'),
                     None)
                ]

        header = make_header(new_value,
                             header_name=header_name,
                             continuation_ws='\t')

    try:
        header.encode()
    except (HeaderParseError, IndexError):
        # despite our best efforts, the header is stuffed
        # HeaderParseError: some very weird multi-line headers
        # IndexError: bug, thrown by make_header(decode_header(' ')).encode()
        return None

    return header
    def _handle_part(self, part, part_index, tmp_dir, extract_attach,
                     parsed_mail):

        bodies = parsed_mail[PROC_EMAIL_JSON_BODIES]
        files = parsed_mail[PROC_EMAIL_JSON_FILES]

        # get the file_name
        file_name = part.get_filename()
        content_disp = part.get('Content-Disposition')
        content_type = part.get('Content-Type')
        content_id = part.get('Content-ID')

        if file_name is None:
            # init name and extension to default values
            name = "part_{0}".format(part_index)
            extension = ".{0}".format(part_index)

            # Try to create an extension from the content type if possible
            if content_type is not None:
                extension = mimetypes.guess_extension(
                    re.sub(';.*', '', content_type))

            # Try to create a name from the content id if possible
            if content_id is not None:
                name = content_id

            file_name = "{0}{1}".format(name, extension)
        else:
            try:
                file_name = str(make_header(decode_header(file_name)))
            except Exception:
                file_name = self._decode_uni_string(file_name, file_name)
        # Remove any chars that we don't want in the name
        file_path = "{0}/{1}_{2}".format(
            tmp_dir, part_index,
            file_name.translate(str.maketrans("", "", ''.join(['<', '>',
                                                               ' ']))))

        self._base_connector.debug_print("file_path: {0}".format(file_path))

        # is the part representing the body of the email
        status, process_further = self._handle_if_body(content_disp,
                                                       content_type, part,
                                                       bodies, file_path,
                                                       parsed_mail)

        if not process_further:
            return phantom.APP_SUCCESS

        # is this another email as an attachment
        if (content_type is not None) and (
                content_type.find(PROC_EMAIL_CONTENT_TYPE_MESSAGE) != -1):
            return phantom.APP_SUCCESS

        # This is an attachment, first check if it is another email or not
        if extract_attach:
            _, file_extension = os.path.splitext(file_name)
            part_payload = part.get_payload(decode=True)
            if not part_payload:
                return phantom.APP_SUCCESS
            try:
                with open(file_path, 'wb') as f:  # noqa
                    f.write(part_payload)
                files.append({'file_name': file_name, 'file_path': file_path})
            except IOError as e:
                error_msg = self._get_error_message_from_exception(e)
                if "File name too long" in error_msg:
                    self.write_with_new_filename(tmp_dir,
                                                 part_payload,
                                                 file_extension,
                                                 files,
                                                 file_name,
                                                 as_byte=False)
                else:
                    self._base_connector.debug_print(
                        'Failed to write file: {}'.format(e))

        return phantom.APP_SUCCESS
示例#55
0
    def __init__(self, smtp_path, whitelist):

        # Initiate logging.
        self.logger = logging.getLogger()

        # Save the whitelist.
        self.whitelist = whitelist

        # Items we parse out of the email.
        self.ace_url = ''
        self.attachments = []
        self.body = ''
        self.cc_addresses = []
        self.envelope_from = ''
        self.envelope_to = ''
        self.from_address = ''
        self.headers = ''
        self.html = ''
        self.indicators = []
        self.message_id = ''
        self.original_recipient = ''
        self.path = smtp_path
        self.received = ''
        self.received_time = ''
        self.remediated = False
        self.reply_to = ''
        self.return_path = ''
        self.screenshots = []
        self.subject = ''
        self.subject_decoded = ''
        self.to_addresses = []
        self.urls = []
        self.x_auth_id = ''
        self.x_mailer = ''
        self.x_original_sender = ''
        self.x_originating_ip = ''
        self.x_sender = ''
        self.x_sender_id = ''
        self.x_sender_ip = ''

        # Build the URL to the ACE alert.
        ace_uuid_pattern = re.compile(
            r'([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})')
        match = ace_uuid_pattern.search(self.path)
        if match:
            self.ace_url = '{}{}'.format(config['ace']['ace_alert_url'],
                                         match.group(1))

        with open(self.path, encoding='utf-8', errors='ignore') as s:
            smtp_stream = s.read().splitlines()

        # Locate any screenshots for this email.
        email_dir = os.path.dirname(self.path)
        files = os.listdir(email_dir)
        for f in files:
            if 'text_html' in f and f.endswith(
                    '.png') and not f.startswith('email_screenshot'):
                self.logger.debug('Found email screenshot: {}'.format(
                    os.path.join(email_dir, f)))
                self.screenshots.append(os.path.join(email_dir, f))

        # Find the envelope from/to addresses. This will only work if given an
        # "smtp.stream" file, since otherwise the SMTP commands will not exist.
        envelope_address_pattern = re.compile(r'.*<(.*)>.*')
        for line in smtp_stream:
            if line.startswith('MAIL FROM:'):
                try:
                    self.envelope_from = envelope_address_pattern.match(
                        line).group(1)
                except:
                    self.logger.exception('Unable to parse envelope from.')
            if line.startswith('RCPT TO:'):
                try:
                    self.envelope_to = envelope_address_pattern.match(
                        line).group(1)
                except:
                    self.logger.exception('Unable to parse envelope to.')

        # Just in case we are dealing with an "smtp.stream" file that still has
        # the SMTP commands above the actual e-mail, we need to strip those out.
        # This will remove all lines prior to the Received: headers so that the
        # email.parser can properly parse out the e-mail. If we were given an
        # "smtp.email" type of file with the SMTP commands already removed, this
        # should not affect anything. This is legacy code at this point.
        try:
            while not smtp_stream[0].startswith('Received:'):
                smtp_stream.pop(0)
        except IndexError:
            smtp_stream = []

        # Join the header lines into a single string.
        self.email_text = '\n'.join(smtp_stream)

        # Create the e-mail object.
        email_obj = email.message_from_string(self.email_text)

        # We want to try and parse an embedded/attached e-mail if there is one.
        # Walk the full e-mail's parts.
        for part in email_obj.walk():
            # Continue if the part looks like a valid e-mail.
            if part.get_content_type() == 'message/rfc822':
                # Split the part lines into a list.
                part_text = str(part).splitlines()
                if any('Received:' in line for line in part_text):
                    # Make sure our part starts with the Received: headers.
                    try:
                        while not part_text[0].startswith('Received:'):
                            part_text.pop(0)
                    except IndexError:
                        pass
                    part_text = '\n'.join(part_text)

                    # Make the new e-mail object.
                    email_obj = email.message_from_string(part_text)

        # Parse the e-mail object for its content.
        parsed_email = self._parse_content(email_obj)

        # Now that we have the e-mail object, parse out some of the interesting parts.
        self.headers = self._get_all_headers_string(email_obj)
        self.received = self.get_header(email_obj, 'received')

        # Get the e-mail's plaintext body, HTML body, and the visible text from the HTML.
        self.body = parsed_email['body']
        self.html = parsed_email['html']

        # Get any e-mail attachments.
        self.attachments = parsed_email['attachments']

        # From address
        try:
            self.from_address = self._get_address_list(email_obj, 'from')[0][1]
            self.indicators.append(
                Indicator('Email - Address',
                          self.from_address,
                          tags=['from_address']))
        except:
            pass

        # From domain
        try:
            self.indicators.append(
                Indicator('URI - Domain Name',
                          self.from_address.split('@')[1],
                          tags=['from_domain']))
        except:
            pass

        # Reply-To address
        try:
            self.reply_to = self._get_address_list(email_obj, 'reply-to')[0][1]
            self.indicators.append(
                Indicator('Email - Address', self.reply_to, tags=['reply_to']))
        except:
            pass

        # X-Sender address
        try:
            self.x_sender = self._get_address_list(email_obj, 'X-Sender')[0][1]
            self.indicators.append(
                Indicator('Email - Address', self.x_sender, tags=['x_sender']))
        except:
            pass

        # X-Sender-Id address
        try:
            self.x_sender_id = self._get_address_list(email_obj,
                                                      'X-Sender-Id')[0][1]
            self.indicators.append(
                Indicator('Email - Address',
                          self.x_sender_id,
                          tags=['x_sender_id']))
        except:
            pass

        # X-Auth-Id address
        try:
            self.x_auth_id = self._get_address_list(email_obj,
                                                    'X-Auth-ID')[0][1]
            self.indicators.append(
                Indicator('Email - Address',
                          self.x_auth_id,
                          tags=['x_auth_id']))
        except:
            pass

        # Return-Path address
        try:
            self.return_path = self._get_address_list(email_obj,
                                                      'return_path')[0][1]
            self.indicators.append(
                Indicator('Email - Address',
                          self.return_path,
                          tags=['return_path']))
        except:
            pass

        # X-MS-Exchange-Organization-OriginalEnvelopeRecipients address
        try:
            self.original_recipient = self._get_address_list(
                email_obj,
                'X-MS-Exchange-Organization-OriginalEnvelopeRecipients'
            )[0][1].lower()
            self.indicators.append(
                Indicator('Email - Address',
                          self.original_recipient,
                          status='Informational',
                          tags=['original_recipient']))
        except:
            pass
        # If the original_recipient was not found, check if this is a POTENTIAL PHISH e-mail and use the from address.
        if not self.original_recipient and 'Subject: [POTENTIAL PHISH]' in self.email_text:
            try:
                temp_email_obj = email.message_from_string(self.email_text)
                self.original_recipient = self._get_address_list(
                    temp_email_obj, 'from')[0][1]
                self.indicators.append(
                    Indicator('Email - Address',
                              self.original_recipient,
                              status='Informational',
                              tags=['original_recipient']))
            except:
                self.logger.exception(
                    'Error parsing original recipient from POTENTIAL PHISH e-mail.'
                )

        # Subject
        try:
            self.subject = ''.join(
                self.get_header(email_obj, 'subject')[0].splitlines())
            if not self.subject.startswith('[POTENTIAL PHISH]'):
                self.indicators.append(
                    Indicator('Email - Subject', self.subject))
        except:
            pass

        # Decoded subject
        try:
            self.subject_decoded = ''.join(
                str(
                    make_header(
                        decode_header(
                            self.get_header(email_obj,
                                            'subject')[0]))).splitlines())
            if not self.subject_decoded.startswith('[POTENTIAL PHISH]'):
                self.indicators.append(
                    Indicator('Email - Subject', self.subject_decoded))
        except:
            pass

        # To addresses
        self.to_addresses = [
            x[1].lower() for x in self._get_address_list(email_obj, 'to')
        ]

        # CC addresses
        self.cc_addresses = [
            x[1].lower() for x in self._get_address_list(email_obj, 'cc')
        ]

        # Message-Id
        try:
            self.message_id = self.get_header(email_obj, 'message-id')[0]
            self.indicators.append(
                Indicator('Email Message ID',
                          self.message_id,
                          status='Informational'))
        except:
            pass

        # X-Mailer
        try:
            self.x_mailer = self.get_header(email_obj, 'x-mailer')[0]
            self.indicators.append(
                Indicator('Email - Xmailer',
                          self.x_mailer,
                          status='Informational'))
        except:
            pass

        # X-Original-Sender address
        try:
            self.x_original_sender = self.get_header(email_obj,
                                                     'x-original-sender')[0]
            self.indicators.append(
                Indicator('Email - Address',
                          self.x_original_sender,
                          tags=['x_original_sender']))
        except:
            pass

        # X-Originating-Ip
        try:
            x_originating_ip = self.get_header(email_obj,
                                               'x-originating-ip')[0]
            # Sometimes this field is in the form: [1.1.1.1]
            # Make sure we remove any non-IP characters.
            ip = RegexHelpers.find_ip_addresses(x_originating_ip)
            if ip:
                self.x_originating_ip = ip[0]
                self.indicators.append(
                    Indicator('Address - ipv4-addr',
                              self.x_originating_ip,
                              tags=['x_originating_ip']))
        except:
            pass

        # X-Sender-Ip
        try:
            x_sender_ip = self.get_header(email_obj, 'x-sender-ip')[0]
            # Make sure like the X-Originating-IP that we only
            # get the IP address and no other characters.
            ip = RegexHelpers.find_ip_addresses(x_sender_ip)
            if ip:
                self.x_sender_ip = ip[0]
                self.indicators.append(
                    Indicator('Address - ipv4-addr',
                              self.x_sender_ip,
                              tags=['x_sender_ip']))
        except:
            pass

        self.received_time = self._get_received_time(email_obj)
        if not self.received_time:
            self.received_time = self._get_date_time()

        # Find any URLs in the plaintext body.
        text_urls = find_urls(self.body)

        # Find any URLs in the HTML body.
        html_urls = find_urls(self.html)

        # Get any strings URLs.
        strings_urls = []
        """
        for file in self.attachments:
            try:
                strings_urls += file['strings_urls']
            except:
                pass
        """

        # Try and remove any URLs that look like partial versions of other URLs.
        all_urls = set.union(text_urls, html_urls)
        unique_urls = set()
        for u in all_urls:
            if not any(
                    other_url.startswith(u) and other_url != u
                    for other_url in all_urls):
                unique_urls.add(u)

        # Get rid of any invalid URLs.
        self.urls = [u for u in unique_urls if RegexHelpers.is_url(u)]

        # Make indicators for the URLs.
        self.indicators += make_url_indicators(self.urls,
                                               from_email_content=True)

        # Get rid of any invalid indicators.
        self.indicators = [i for i in self.indicators if i.value]

        # Add any extra tags to each indicator.
        for i in self.indicators:
            i.tags.append('phish')
示例#56
0
 def _read_source(imap_host, imap_port, imap_user, imap_pass, imap_folder,
                  email_inreply):
     source = {'alreadyLoaded': False}
     try:  ## Time to search for the original email
         try:
             if "gmail" in imap_host:  # gmail server requires an ssl connection
                 print("gmail server")
                 imap = IMAP4_SSL(imap_host, imap_port)
             else:
                 imap = IMAP4_SSL(imap_host, imap_port)
             ## login to server
             #print(imap_user, imap_pass)
             imap.login(imap_user, imap_pass)
             #imap.starttls()
         except:
             print("Failed to login")
             return False
         # while 'INBOX' is standard, many email servers use different methods to label the Sent folder
         # We have to iterate through the most common methods to find the right one
         if "gmail" in imap_host:
             imap.select('"[Gmail]/Sent Mail"')  # connect to sent mail.
             # Search for the original email ID
             messages = imap.search(None, 'HEADER', 'MESSAGE-ID',
                                    email_inreply)
             #print("Opening gmail 'Sent'")
         if 'gmail' not in imap_host:
             sentbox = False
             try:
                 imap.select('Sent')  # connect to sent mail.
                 # Search for the original email ID
                 messages = imap.search(None, 'HEADER', 'MESSAGE-ID',
                                        email_inreply)
                 sentbox = True
             except:
                 print('Sent folder not found')
             if sentbox == False:
                 try:
                     imap.select('INBOX.Sent')  # connect to sent mail.
                     # Search for the original email ID
                     messages = imap.search(None, 'HEADER', 'MESSAGE-ID',
                                            email_inreply)
                 except:
                     print(
                         'Inbox.Sent folder not found, no folders left to try'
                     )
         # Process the result to get the message id’s
         messages = messages[1][0].split()
         # Use the first id to view the headers for a message
         result, source_data = imap.fetch(messages[0], '(RFC822)')
         #print("Opening 'Sent'", messages[0])
         raw_source = source_data[0][
             1]  # here's the body, which is raw headers and html and body of the whole email
         s = email.message_from_bytes(
             raw_source)  # convert to message object
         source_subject = s['subject']
         try:
             sub = make_header(decode_header(source_subject))
         except:
             sub = email_subject
         source['subject'] = str(sub)
         print(source_subject)
         frm = s['From']
         add1 = re.findall(
             "([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+)", str(frm))
         source['email'] = add1
         if s['Date'] != None:
             source['_date'] = s['Date']
         if s['Delivery-date'] != None:
             source['_date'] = s['Delivery-date']
         source['bcc'] = ''
         if s['bcc'] != None:
             print("bcc is: ", s['bcc'])
             source['bcc'] = s['bcc'].split(',')
         source['msg_id'] = s['Message-ID']
         #print("BCC from source: ", source_bcc)
         source_body = s.get_payload(decode=True)
         if s.is_multipart():  # search for text in the body
             for part in s.walk():
                 ctype = part.get_content_type()
                 cdispo = str(part.get('Content-Disposition'))
                 if ctype == ('text/plain' or
                              'text/html') and 'attachment' not in cdispo:
                     source_body = part.get_payload(decode=True)
                     #print(email_body)
                     break
         src_from = BeautifulSoup(frm, 'html.parser')
         try:  # extra check for encryption (in case user has encypted email)
             src_body = BeautifulSoup(source_body, 'html.parser')
             text = src_body.get_text()
             urls = re.findall(
                 'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+',
                 text)
             # break into lines and remove leading and trailing space on each
             lines = (line.strip() for line in text.splitlines())
             # drop blank lines
             text = '\n'.join(line for line in lines if line)
             # double space new lines
             text = text.replace('\n', '\n\n')
             source['nomarkup_body'] = text
             for i in urls:
                 text = text.replace(
                     i,
                     f"[ref=<{i}>][color=6666FF][u]{i}[/u][/color][/ref]")
             source['body'] = text  #.encode('utf-8')
         except:  # if email is encrypted it will throw an exception
             source['body'] = encription_warning
         source['from'] = src_from.get_text().split('@')[0]
         ids_list.append(source['msg_id'])
         return source
     except:
         print("no origin found")
         return False
    def _add_body_in_email_headers(self, parsed_mail, file_path, charset,
                                   content_type):

        # Add email_bodies to email_headers
        email_headers = parsed_mail[PROC_EMAIL_JSON_EMAIL_HEADERS]

        try:
            with open(file_path, 'r') as f:
                body_content = f.read()
        except Exception:
            with open(file_path, 'rb') as f:
                body_content = f.read()
            self._base_connector.debug_print(
                "Reading file data using binary mode")
        # Add body to the last added Email artifact
        body_content = UnicodeDammit(body_content).unicode_markup.encode(
            'utf-8').decode('utf-8')
        if 'text/plain' in content_type:
            try:
                email_headers[-1]['cef']['bodyText'] = self._get_string(
                    body_content, charset)
            except Exception as e:
                try:
                    email_headers[-1]['cef']['bodyText'] = str(
                        make_header(decode_header(body_content)))
                except Exception:
                    email_headers[-1]['cef'][
                        'bodyText'] = self._decode_uni_string(
                            body_content, body_content)
                error_code, error_msg = self._get_error_message_from_exception(
                    e)
                err = "Error occurred while parsing text/plain body content for creating artifacts"
                self._base_connector.debug_print("{}. {}. {}".format(
                    err, error_code, error_msg))

        elif 'text/html' in content_type:
            try:
                email_headers[-1]['cef']['bodyHtml'] = self._get_string(
                    body_content, charset)
            except Exception as e:
                try:
                    email_headers[-1]['cef']['bodyHtml'] = str(
                        make_header(decode_header(body_content)))
                except Exception:
                    email_headers[-1]['cef'][
                        'bodyHtml'] = self._decode_uni_string(
                            body_content, body_content)
                error_code, error_msg = self._get_error_message_from_exception(
                    e)
                err = "Error occurred while parsing text/html body content for creating artifacts"
                self._base_connector.debug_print("{}. {}. {}".format(
                    err, error_code, error_msg))

        else:
            if not email_headers[-1]['cef'].get('bodyOther'):
                email_headers[-1]['cef']['bodyOther'] = {}
            try:
                email_headers[-1]['cef']['bodyOther'][
                    content_type] = self._get_string(body_content, charset)
            except Exception as e:
                try:
                    email_headers[-1]['cef']['bodyOther'][content_type] = str(
                        make_header(decode_header(body_content)))
                except Exception:
                    email_headers[-1]['cef']['bodyOther'][
                        content_type] = self._decode_uni_string(
                            body_content, body_content)
                error_code, error_msg = self._get_error_message_from_exception(
                    e)
                err = "Error occurred while parsing bodyOther content for creating artifacts"
                self._base_connector.debug_print("{}. {}. {}".format(
                    err, error_code, error_msg))
示例#58
0
 def _read_mail(imap_host, imap_port, imap_user, imap_pass, imap_folder,
                eNum):  # reads the most recent email and parses the text
     ### Reading emails from the server. The bulk of the logic is here
     ### We prosses an email, clean up the text, check if it is a reply
     ### If the message is a reply, search for the original email in the sent box
     ### If the original email exists, run a search on the inbox for all emails replying to the original
     ### And finally, check for and load images
     global ids_list
     if eNum == -1:
         ids_list = []
     email_recieved = {'alreadyLoaded': False}
     try:
         imap = IMAP4_SSL(imap_host, imap_port)
         ## login to server
         print(imap_user, imap_pass)
         imap.login(imap_user, imap_pass)
         #imap.ehlo()
         #imap.starttls()
     except:
         print("Failed to login")
         return False
     #print(imap.list()) # for identifying mailboxes on the server
     imap.select()
     result, data = imap.uid('search', None,
                             "ALL")  # search and return uids instead
     #print('data', data)
     if -len(data[0].split()) > eNum:
         return False
     current_email_uid = data[0].split()[eNum]
     print('current', current_email_uid)
     result, data = imap.uid(
         'fetch', current_email_uid, '(RFC822)'
     )  # fetch the email headers and body (RFC822) for the given ID
     raw_email = data[0][
         1]  # here's the body, which is raw headers and html and body of the whole email
     b = email.message_from_bytes(raw_email, policy=email.policy.default)
     email_recieved['msg_id'] = b['Message-ID']
     for i in ids_list:
         if i == email_recieved['msg_id']:
             print("mail already loaded")
             email_recieved['alreadyLoaded'] = True
             return email_recieved
     ids_list.append(email_recieved['msg_id'])
     print(email_recieved['msg_id'])
     email_recieved['date'] = b['Date']
     if email_recieved['date'] == None:
         email_recieved['date'] = b['Delivery-date']
     email_recieved['inreply'] = b['in-reply-to']
     email_recieved['refs'] = b['references']
     # decode and clean the name out of the From header
     email_from = b['from']
     # get just the text
     frm = BeautifulSoup(email_from, 'html.parser')
     frm = frm.get_text()
     # remove any latent escape chrs
     frm = make_header(decode_header(frm))
     # remove unneccisary quotes
     frm = str(frm).replace('"', '')
     # add result to list
     email_recieved['from'] = str(frm)
     # find all email addresses in the From header
     add1 = re.findall("([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+)",
                       str(email_from))
     email_recieved['email'] = add1  # is a list
     # clean the subject text
     email_subject = b['Subject']
     try:
         sub = make_header(decode_header(email_subject))
     except:
         sub = email_subject
     email_recieved['subject'] = str(sub)
     # find and clean up the body text
     email_body = b.get_payload(decode=True)
     if b.is_multipart():  # search for text in the body
         for part in b.walk():
             ctype = part.get_content_type()
             cdispo = str(part.get('Content-Disposition'))
             if ctype == ('text/plain'
                          or 'text/html') and 'attachment' not in cdispo:
                 email_body = part.get_payload(decode=True)
                 #print(email_body)
                 break
     # Use beautifulsoup to get readable text
     try:  # Try parsing the body text
         body = BeautifulSoup(email_body, 'html.parser')
     except:  # if email is encrypted it will throw an exception
         body = encription_warning
     if body != encription_warning:
         for script in body(["script", "style", "div", "div style"]):
             script.extract()  # rip it out
         text = body.get_text()
         urls = re.findall(
             'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+',
             text)
         # replace and remove leftover html escape chrs, bad wiziwig
         text = text.replace('=0A', '\n')
         text = text.replace('=20', '\n')
         text = text.replace('=\r\n', '')
         text = text.replace('=\n', '')
         text = text.replace('=C2=A0', '')
         text = text.replace('=C2=A9', '')
         text = text.replace('=09', '')
         text = text.replace('=0D', '')
         text = text.replace('<td>', '')
         text = text.replace('</td>', '')
         text = text.replace('<tr>', '')
         text = text.replace('</a>', '')
         # break into lines and remove leading and trailing space on each
         lines = (line.strip() for line in text.splitlines())
         # drop blank lines
         text = '\n'.join(line for line in lines if line)
         # double space new lines
         text = text.replace('\n', '\n\n')
         email_recieved['nomarkup_body'] = text
         for i in urls:
             text = text.replace(
                 i, f"[ref=<{i}>][color=6666FF][u]{i}[/u][/color][/ref]")
     email_recieved['body'] = text
     imap.close()
     return email_recieved
示例#59
0
    items = get_messages()

    if len(items) != 0:
        for item in items:
            resp, data = m.fetch(item, '(RFC822)')
            mail_full = email.message_from_bytes(data[0][1])
            if mail_full.is_multipart():
                for part in mail_full.get_payload():
                    mail = mail_full.get_payload()[0].get_payload(
                        decode=True).decode()
            else:
                mail = mail_full.get_payload(decode=True).decode()
            parse = parse_html(mail)
            mail_from = parseaddr(mail_full['From'])[1]
            mail_from = mail_full['X-Envelope-From']
            mail_subj = str(make_header(decode_header(mail_full['Subject'])))
            if mail_from == sender:
                if parse[0]:
                    download_res, name = download_file(parse[1])
                    if download_res:
                        extract_res, txt_name = extract(name)
                        if extract_res:
                            admin_notify(
                                "✅ Файл-выписка успешно загружена и распакована!  \n`{}  \n{}`"
                                .format(str(name), str(txt_name)))
                        else:
                            admin_notify(
                                "‼ *Ошибка!* `Не удалось распаковать файл.`")
                    else:
                        admin_notify(
                            "‼ *Ошибка!* `Ссылка недоступна для скачивания.`")
    def getMailDetail(self, mailId):
        # == 未送信メールを処理
        result = {}
        ## メッセージ取得(ヘッダ・本文)
        typ, data = self.ImapInstance.uid('fetch', mailId, '(RFC822)')
        if typ != 'OK':
            raise IMAPCommandError(
                'search', 'I cannot get Mail data of number' + mailId + "." +
                '\n responce: ' + typ)

        ## ログ出力ぅ
        """
        print('mail['+str(mailId)+']')
        for i in range(len(data)):
            for j in range(len(data[i])):
                if type(data[i][j])==bytes:
                    print("data["+str(i)+"]"+"["+str(j)+"]"+str(data[i][j].decode('iso2022_jp')))
                else:
                    print("data["+str(i)+"]"+"["+str(j)+"]"+str(data[i][j]))
        """

        ## emailライブラリに渡す
        email_message = email.message_from_bytes(data[0][1])

        ## データ抽出
        ### From
        From_Address = str(make_header(decode_header(email_message['From'])))
        From_Name = ''
        if "<" in From_Address:
            tmp_f = From_Address.split("<")
            From_Name = tmp_f[0]
            From_Address = tmp_f[1].split(">")[0]
        ### To
        To_Address = str(make_header(decode_header(email_message['To'])))
        To_Name = ''
        if "<" in To_Address:
            tmp_t = To_Address.split("<")
            To_Name = tmp_t[0]
            To_Address = tmp_t[1].split(">")[0]
        ### Subject
        Subject = str(make_header(decode_header(email_message['Subject'])))

        ### ログ出力
        print('                                  > ' + str(mailId.hex()) +
              ':' + Subject + ' ' + From_Address + '<' + From_Name + '> ' +
              To_Address + '<' + To_Name + '>')

        ### 本文抽出
        #### 本文取得
        body = ''
        SucceedFlag = False
        try:
            if email_message.is_multipart() == False:  # シングルパート
                print(
                    '                                     - getting body as single part'
                )
                byt = bytearray(email_message.get_payload(), 'iso2022_jp')
                body = byt.decode(encoding='iso2022_jp')
            else:  # マルチパート
                print(
                    '                                     - getting body as multi part'
                )
                prt = email_message.get_payload()[0]
                byt = prt.get_payload(decode=True)
                body = byt.decode(encoding='iso2022_jp')
            print(
                '                                     - body decode succeed!')
            SucceedFlag = True
        except Exception as err_inst:
            body = 'メールを受信しましたが変換できませんでした\n\nエラーログ:\n' + str(
                err_inst.__class__.__name__) + ":" + str(err_inst)
            print(str(err_inst.__class__.__name__) + str(err_inst))

        #TODO ここ埋めれるように頑張る
        result['Succeed'] = SucceedFlag
        result['UID'] = mailId.hex()
        result['Subject'] = Subject
        result['Body'] = body
        result['From_Address'] = From_Address
        result['From_Name'] = From_Name
        result['To_Address'] = To_Address
        result['To_Name'] = To_Name
        return result