How to implement Python mail delivery (Basic article)

Source: Internet
Author: User
Tags base64 rfc822


Here's the main code:

Initialize, define mail server

Self. Imap_server= ' imap.gmail.com '
Self. imap_port=993
Self. M = None
Self.response
Self.mailboxes = []
Login, select mailbox:

Self. M = Imaplib. Imap4_ssl (self. Imap_server, self. Imap_por
RC, self.response = self. M.login (username, password)
Tye,data = M.m.select ()
Mail search:

RET, msgnums = M.m.search (None, ' body ', datapath)
Get message information:

Status, Response = self. M.fetch (ID, "(RFC822)")
Mailtext = response[0][1]
Mail_message = email.message_from_string (Mailtext)
Subject = Unicode (email. Header.make_header (email. Header.decode_header (mail_message[' subject '))
#print "subject_________:" +subject
Mail_from = Email.utils.parseaddr (mail_message["from"]) [1]
mail_to = Email.utils.parseaddr (mail_message["to"]) [1]
Time = mail_message[' Date ']
print ' [' +mail_message[' Date ']+ '] ' + ' \ n ' from: ' +mail_from+ ' to: ' +mail_to+ ' + ' Subject: ' +subject+ ' \ n '
Return Self.get_first_text_block (mail_message), subject, Mail_from, time
MainType = Email_message_instance.get_content_maintype () return the content of the message is what type, if the text is better to deal with, if it is multipart, also have to traverse Email_ Message_instance to be processed according to different types.

Email.message_from_string (Mailtext) Returns a structure that contains basic information about the message

The pain in the mail is the problem of string coding, after all, everyone's message format is not the same, some are Unicode, some are utf-8, some are gb2312, there are accessories, pictures and many other formats,

Of course, this time only to deal with the text, there is no need to deal with attachments and pictures of these. I am all unified to convert the character to Unicode to deal with.

String processing, you can use Chardet to determine the type of string, read and write files can be used to specify the type of read-write character codecs

Add three examples




Example 1


From Project Georegistry, under Directory Georegistry/lib, in source file smtp.py.


Score:13


Vote


Vote


Def SendMessage (Frombyvalue, tobyvalue, subject, Body, Headerbyname=none):


' Send a message using SMTP '


# Prepare


message = Email.message.Message ()


Message.add_header (' From ', Email.utils.formataddr (frombyvalue[' nickname ', frombyvalue[' email '))


Message.add_header (' to ', Email.utils.formataddr (tobyvalue[' nickname ', tobyvalue[' email '))


Message.add_header (' Subject ', subject)


Message.set_payload (body)


If Headerbyname:


For key, value in Headerbyname.iteritems ():


Message.add_header (key, value)


# Connect to Server


If frombyvalue[' smtp '] = = ' localhost ':


Server = Smtplib. SMTP (' localhost ')


Else


Server = Smtplib. Smtp_ssl (frombyvalue[' SMTP '), 465)


If Len (frombyvalue[' username ']):


Server.login (frombyvalue[' username '), frombyvalue[' password ']


# Send Mail


Try


Server.sendmail (frombyvalue[' email '), tobyvalue[' email '], message.as_string ()


Except Socket.error, error:


Raise Smtperror (Error)


Finally


Server.quit ()


Example 2


From Project Appengine-python3-master, under Directory google/appengine/tools/devappserver2/admin, in source file Mail_ request_handler_test.py.


Score:10


Vote


Vote


def test_send (self):


Self.mox.StubOutWithMock (Mail_request_handler. Mailrequesthandler,


' Dispatcher ')


Handler = Mail_request_handler. Mailrequesthandler (None, none)


Handler.dispatcher = Self.mox.CreateMock (dispatcher. Dispatcher)


Handler.dispatcher.add_request (


Method= ' POST ',


Relative_url= ' URL ',


headers=[(' Content-type ', ' message/rfc822 ')],


body= ' mail message ',


source_ip= ' 0.1.0.20 ')


Message = Self.mox.CreateMock (email.message.Message)


Message.as_string (). Andreturn (' mail message ')


Self.mox.ReplayAll ()


Handler._send (' URL ', message)


Self.mox.VerifyAll ()

Example 3


From Project Python-sipsimple-master, under Directory sipsimple/streams/applications, in source file chat.py.


Score:8


Vote


Vote


def __str__ (self):


headers = []


If Self.sender:


Headers.append (U ' from:%s '% self.sender)


For recipient in self.recipients:


Headers.append (U ' to:%s '% recipient)


For recipient in self.courtesy_recipients:


Headers.append (U ' cc:%s '% recipient)


If Self.subject:


Headers.append (U ' Subject:%s '% self.subject)


If Self.subject is not None:


For Lang, translation in Self.subject.translations.iteritems ():


Headers.append (U ' subject:;lang=%s%s '% (lang, translation))


If Self.timestamp:


Headers.append (U ' DateTime:%s '% self.timestamp)


If self.required:


Headers.append (U ' Required:%s '% ', '. Join (self.required))


namespaces = {u ': self.standard_namespace}


For header in Self.additional_headers:


If Namespaces.get (Header.namespace.prefix, None)!= header.namespace:


If Header.namespace.prefix:


Headers.append (U ' NS:%s <%s> '% (Header.namespace.prefix, header.namespace))


Else


Headers.append (U ' NS: <%s> '% header.namespace)


Namespaces[header.namespace.prefix] = Header.namespace


If Header.namespace.prefix:


Headers.append (U '%s.%s:%s '% (Header.namespace.prefix, Header.name, Header.value))


Else


Headers.append (U '%s:%s '% (Header.name, header.value))


Headers.append (U ')


headers = ' \ r \ n '. Join (S.encode (' Cpim-headers ') for s in headers)

message = Message ()
Message.set_type (Self.content_type)
If Isinstance (Self.body, Unicode):
Message.set_param (' CharSet ', ' utf-8 ')
Message.set_payload (Self.body.encode (' Utf-8 '))
Else
Message.set_payload (Self.body)

return headers + ' \ r \ n ' + message.as_string ()

Example 4


From Project Odoo, under Directory Addons/mail, in source file mail_thread.py.


Score:8


Vote


Vote


def _message_extract_payload (self, Message, Save_original=false):


"" "Extract body as HTML and attachments from" ""


attachments = []


BODY = U ' "


If save_original:


Attachments.append ((' Original_email.eml ', message.as_string ())


If not Message.is_multipart () or ' text/' in Message.get (' Content-type ', '):


encoding = Message.get_content_charset ()


BODY = Message.get_payload (decode=true)


BODY = TOOLS.USTR (body, encoding, errors= ' replace ')


If message.get_content_type () = = ' Text/plain ':


# Text/plain-> <pre/>


BODY = tools.append_content_to_html (U ", Body, Preserve=true)


Else


Alternative = False


For part in Message.walk ():


If part.get_content_type () = = ' Multipart/alternative ':


Alternative = True


If part.get_content_maintype () = = ' multipart ':


Continue # Skip Container


# Part.get_filename returns decoded value if able to decode, coded otherwise.


# Original Get_filename is isn't able to decode Iso-8859-1 (for instance).


# Therefore, ISO encoded attachements are not able to is decoded properly with Get_filename


# code here partially copy of the original Get_filename method, but handle more encoding


Filename=part.get_param (' filename ', None, ' content-disposition ')


If not filename:


Filename=part.get_param (' name ', None)


If filename:


If isinstance (filename, tuple):


# RFC2231


Filename=email.utils.collapse_rfc2231_value (filename). Strip ()


Else


Filename=decode (filename)


encoding = Part.get_content_charset () # None-If attachment


# 1) Explicit Attachments-> Attachments


If filename or part.get (' content-disposition ', '). Strip (). StartsWith (' attachment '):


Attachments.append ((filename or ' attachment ', Part.get_payload (decode=true))


Continue


# 2) Text/plain-> <pre/>


If part.get_content_type () = = ' Text/plain ' and (not alternative or not):


BODY = tools.append_content_to_html (the body, Tools.ustr (Part.get_payload (decode=true),


Encoding, errors= ' replace '), preserve=true)


# 3) text/html-> Raw


Elif Part.get_content_type () = = ' text/html ':


html = TOOLS.USTR (Part.get_payload (decode=true), encoding, errors= ' replace ')


If alternative:


BODY = html


Else


BODY = tools.append_content_to_html (body, HTML, Plaintext=false)


# 4) Anything else-> attachment


Else


Attachments.append ((filename or ' attachment ', Part.get_payload (decode=true))


return body, attachments

Example 5

From Project OPENERP-KTV, under Directory Openerp/addons/mail, in source file mail_message.py.
Score:5

Vote
Vote
def parse_message (self, Message, Save_original=false):
"" "parses a string or email.message.Message representing an
RFC-2822 email, and returns a generic dict holding the
Message details.

:p Aram Message:the Message to parse


: Type Message:email.message.Message | string | Unicode


:p Aram BOOL Save_original:whether the returned dict


Should include an ' original ' entry with the Base64


Encoded source of the message.


: rtype:dict


: Return:a dict with the following structure, where each


Field May is present if missing in original


Message::

{' Message-id ': msg_id,


' Subject ': Subject,


' From ':


"To": To,


' CC ': CC,


' Headers ': {' X-mailer ': Mailer,


#.. All x-headers ...


},


' Subtype ': Msg_mime_subtype,


' Body_text ': plaintext_body


' body_html ': html_body,


' Attachments ': [(' file1 ', ' bytes '),


(' file2 ', ' bytes ')}


# ...


' Original ': Source_of_email,


}


"""


Msg_txt = Message


If isinstance (message, str):


Msg_txt = email.message_from_string (message)

# warning:message_from_string doesn ' t always work correctly on Unicode,
# We must use UTF-8 strings here:-(
If Isinstance (message, Unicode):
message = Message.encode (' Utf-8 ')
Msg_txt = email.message_from_string (message)

message_id = Msg_txt.get (' Message-id ', False)
msg = {}

        if save_original:
             # Save original, we need to is able to read the original email sometimes
   &N bsp;        msg[' original '] = message.as_string () If isinstance (message, message) \
                                                    Else Message
             msg[' original '] = Base64.b64encode (msg[' original ')) # Binary fields are b64

If not message_id:
# Very Unusual situation, be we should being fault-tolerant here
message_id = Time.time ()
msg_txt[' message-id '] = message_id
_logger.info (' parsing message without message-id, generating a random one:%s ', message_id)

Fields = Msg_txt.keys ()
msg[' id '] = message_id
msg[' message-id '] = message_id

If ' Subject ' in fields:
msg[' subject '] = Decode (msg_txt.get (' subject '))

If ' Content-type ' in fields:
msg[' content-type '] = msg_txt.get (' Content-type ')

If ' from ' in fields:
Msg[' from '] = decode (Msg_txt.get (' from ') or Msg_txt.get_unixfrom ())

If ' to ' in fields:
Msg[' to '] = decode (Msg_txt.get (' to '))

If ' delivered-to ' in fields:
Msg[' to '] = decode (msg_txt.get (' delivered-to '))

If ' CC ' in fields:
msg[' cc ' = Decode (Msg_txt.get (' cc '))

If ' Cc ' in fields:
msg[' cc ' = Decode (Msg_txt.get (' cc '))

If ' reply-to ' in fields:
msg[' reply '] = decode (msg_txt.get (' reply-to '))

If ' Date ' in fields:


Try


DATE_HDR = Decode (Msg_txt.get (' Date '))


Parsed_date = Dateutil.parser.parse (DATE_HDR, Fuzzy=true)


If Parsed_date.utcoffset () is None:


# naive DateTime, so we arbitrarily decide to make it


# UTC, there ' s no better choice. Should not happen,


# as RFC2822 requires timezone offset in Date headers.


Stored_date = Parsed_date.replace (TZINFO=PYTZ.UTC)


Else


Stored_date = Parsed_date.astimezone (PYTZ.UTC)


Except Exception:


_logger.warning (' Failed to parse Date header%r in incoming mail '


' With Message-id%r, assuming current date/time. ',


Msg_txt.get (' Date '), message_id)


Stored_date = Datetime.datetime.now ()





msg[' Date ' = Stored_date.strftime ("%y-%m-%d%h:%m:%s")

If ' content-transfer-encoding ' in fields:
msg[' encoding '] = msg_txt.get (' content-transfer-encoding ')

If ' References ' in fields:
msg[' references '] = Msg_txt.get (' References ')

If ' in-reply-to ' in fields:
msg[' in-reply-to '] = msg_txt.get (' in-reply-to ')

msg[' headers '] = {}


msg[' subtype '] = ' plain '


For item in Msg_txt.items ():


If Item[0].startswith (' x '):


msg[' headers '].update ({item[0]: item[1]})


If not Msg_txt.is_multipart () or ' Text/plain ' in Msg.get (' Content-type ', '):


encoding = Msg_txt.get_content_charset ()


BODY = Tools.ustr (Msg_txt.get_payload (decode=true), encoding, errors= ' replace ')


If ' text/html ' in Msg.get (' Content-type ', '):


msg[' body_html ' = body


msg[' subtype ' = ' html '


BODY = Tools.html2plaintext (body)


msg[' body_text '] = tools.ustr (body, encoding, errors= ' replace ')

attachments = []


If Msg_txt.is_multipart () or ' multipart/alternative ' in Msg.get (' Content-type ', '):


BODY = ""


If ' multipart/alternative ' in Msg.get (' Content-type ', '):


msg[' subtype '] = ' alternative '


Else


msg[' subtype '] = ' mixed '


For part in Msg_txt.walk ():


If part.get_content_maintype () = = ' multipart ':


Continue

encoding = Part.get_content_charset ()


filename = Part.get_filename ()


If part.get_content_maintype () = = ' Text ':


Content = Part.get_payload (decode=true)


If filename:


Attachments.append ((filename, content))


Content = tools.ustr (content, encoding, errors= ' replace ')


If part.get_content_subtype () = = ' html ':


msg[' body_html '] = content


msg[' subtype '] = ' HTML ' # HTML version prevails


BODY = tools.ustr (tools.html2plaintext (content))


BODY = Body.replace (' & #13; ', ')


Elif Part.get_content_subtype () = = ' Plain ':


BODY = Content


Elif Part.get_content_maintype () in (' Application ', ' image '):


If filename:


Attachments.append ((Filename,part.get_payload (decode=true))


Else


res = Part.get_payload (decode=true)


Body + = TOOLS.USTR (res, encoding, errors= ' replace ')

msg[' body_text ' = body
msg[' attachments '] = attachments

# for backwards compatibility:
msg[' body '] = msg[' Body_text ']
msg[' sub_type '] = msg[' subtype '] or ' plain '
Return msg

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.