Example #1
0
    def set_body(self, html=None, plain=None):
        cur_ctype = self.get_content_type()
        cur_maintype, cur_subtype = cur_ctype.split("/")

        flag = 0b00
        if html is not None:
            htmlmsg = MIMEText(html, _subtype='html')
            flag |= 0b10
        if plain is not None:
            plainmsg = MIMEText(plain, _subtype='plain')
            flag |= 0b01

        if flag == 0b11:
            altmsg = MIMEMultipart('alternative')
            altmsg.attach(htmlmsg)
            altmsg.attach(plainmsg)

        if cur_ctype == "multipart/mixed":
            if flag == 0b01:
                # POTENTIAL BUG: does it matter if there is already a body payload?
                self.attach(plainmsg)
            elif flag == 0b10:
                # POTENTIAL BUG: ditto
                self.attach(htmlmsg)
            elif flag == 0b11:
                # POTENTIAL BUG: ditto
                self.attach(altmsg)
            else:
                raise Exception("YOU ARE NOT SUPPOSED TO BE HERE")

        elif cur_ctype == 'multipart/alternative':
            if flag == 0b01:
                self.set_payload(plainmsg.get_payload())
                self['Content-Type'] = 'text/plain'
            elif flag == 0b10:
                self.set_payload(htmlmsg.get_payload())
                self['Content-Type'] = 'text/html'
            elif flag == 0b11:
                self.set_payload(altmsg.get_payload())
            else:
                raise Exception("YOU ARE NOT SUPPOSED TO BE HERE")

        elif cur_ctype.startswith('text'):
            if flag == 0b01:
                self.set_payload(plainmsg.get_payload())
                if cur_ctype.endswith('html'):
                    self['Content-Type'] = 'text/plain'
            elif flag == 0b10:
                self.set_payload(htmlmsg.get_payload())
                if cur_ctype.endswith('plain'):
                    self['Content-Type'] = 'text/html'
            elif flag == 0b11:
                self.make_alternative()
                #self['Content-Type'] = 'multipart/alternative'
                self.set_payload(altmsg.get_payload())
            else:
                raise Exception("YOU ARE NOT SUPPOSED TO BE HERE")
    def test_add_image_void_no_action(self):
        """ message payload must be void """
        email_builder = EmailBuilder("localhost", 8000, "sender_email", "receiver_email")
        message = MIMEMultipart()

        email_builder._add_image(None, message)
        self.assertTrue(0 == len(message.get_payload()))

        email_builder._add_image([], message)
        self.assertTrue(0 == len(message.get_payload()))
Example #3
0
def send_email(frm, to, subject, body, attachments=None):
    """
    Send email, only possible to ASTRON addresses

    :param str frm: From address
    :param str/list to: To addresses, either single or list of addresses
    :param str subject: Subject of email
    :param dict body: Dict with e-mail content (str) and type (str)
    :param dict/list attachments: optional dict or list of dicts with attachment path (str), type (str), and name (str)
    """

    # ensure "to" is a single string
    if isinstance(to, list):
        to_str = ', '.join(to)
    else:
        to_str = to

    # init email
    msg = MIMEMultipart('mixed')
    # set to, from, subject
    msg['To'] = to_str
    msg['From'] = frm
    msg['Subject'] = subject

    # add body
    msg.attach(MIMEText(body['content'], body['type']))

    # add attachments
    if attachments is not None:
        # ensure it is a list
        if not isinstance(attachments, list):
            attachments = [attachments]
        for attachment in attachments:
            fname = attachment['path']
            name = attachment['name']
            typ = attachment['type']
            # load the file
            with open(fname, 'rb') as f:
                part = MIMEApplication(f.read(), typ)
                # set filename
                part[
                    'Content-Disposition'] = 'attachment; filename="{}"'.format(
                        name)
            # attach to email
            msg.attach(part)

    # send the e-mail
    smtp = smtplib.SMTP()
    smtp.connect()
    try:
        smtp.sendmail(frm, to, msg.as_string())
    except smtplib.SMTPSenderRefused:
        # assume failed because messages is too big
        # so send again without attachments
        # first element of payload is main text, rest are the attachments
        msg.set_payload(msg.get_payload()[0])
        # send again
        smtp.sendmail(frm, to, msg.as_string())

    smtp.close()
    def test_add_image_file_not_empty(self):
        """ message payload must be not emppty  """
        email_builder = EmailBuilder("localhost", 8000, "sender_email", "receiver_email")
        message = MIMEMultipart()
        email_builder._add_image([b'01'], message)

        self.assertTrue(1 == len(message.get_payload()))
def sendConfirm_thread(email, token, name=None):
    email_server = validateAndGetField('EMAIL_SERVER')
    sender = validateAndGetField('EMAIL_FROM_ADDRESS')
    sender_name = validateAndGetField('EMAIL_SENDER_NAME', raise_error=False)
    domain = validateAndGetField('EMAIL_PAGE_DOMAIN')
    subject = validateAndGetField('EMAIL_MAIL_SUBJECT')
    address = validateAndGetField('EMAIL_ADDRESS')
    port = validateAndGetField('EMAIL_PORT', default_type=int)
    password = validateAndGetField('EMAIL_PASSWORD')
    mail_plain = validateAndGetField('EMAIL_MAIL_PLAIN', raise_error=False)
    mail_html = validateAndGetField('EMAIL_MAIL_HTML', raise_error=False)

    if not (
            mail_plain or mail_html
    ):  # Validation for mail_plain and mail_html as both of them have raise_error=False
        raise NotAllFieldCompiled(
            f"Both EMAIL_MAIL_PLAIN and EMAIL_MAIL_HTML missing from settings.py, at least one of them is required."
        )

    domain += '/' if not domain.endswith('/') else ''

    msg = MIMEMultipart('alternative')
    msg['Subject'] = subject
    msg['From'] = formataddr(
        (sender_name.title(), sender)) if sender_name else sender
    msg['To'] = email

    from .views import verify
    http_protocol = "http://" if not domain.startswith("http") else ''
    link = f'{http_protocol}{domain}verify/{token}'
    for k, v in get_resolver(None).reverse_dict.items():
        if k is verify and v[0][0][1][0]:
            addr = str(v[0][0][0])
            link = domain + addr[0:addr.index('%')] + token

    email_data = {'link': link, 'name': name, 'domain': domain.strip('/')}
    if mail_plain:
        try:
            text = render_to_string(mail_plain, email_data)
            part1 = MIMEText(text, 'plain')
            msg.attach(part1)
        except AttributeError:
            pass

    if mail_html:
        try:
            html = render_to_string(mail_html, email_data)
            part2 = MIMEText(html, 'html')
            msg.attach(part2)
        except AttributeError:
            pass

    if not msg.get_payload():
        raise EmailTemplateNotFound('No email template found')

    server = SMTP(email_server, port)
    server.starttls()
    server.login(address, password)
    server.sendmail(sender, email, msg.as_string())
    server.quit()
    def test_add_two_images_file_check_fields(self):
        """ message payload must have two images header  """
        email_builder = EmailBuilder("localhost", 8000, "sender_email", "receiver_email")
        message = MIMEMultipart()
        email_builder._add_image([b'0', b'0'], message)

        self.assertTrue(2 == len(message.get_payload()))

        for idx, base in enumerate(message.get_payload()):
            base_str = base.as_string()
            idx_str = str(idx)

            self.assertTrue('image/png' in base_str)
            self.assertTrue('filename="chart-image' + idx_str + '.png"' in base_str)
            self.assertTrue('X-Attachment-Id: ' + idx_str in base_str)
            self.assertTrue('Content-ID: <' + idx_str + '>' in base_str)
Example #7
0
class Email(object):
    def __init__(self, ctx, repo, cache):
        self.recipients = ctx.getEmail(repo)
        self.mailfrom = ctx.getMailFrom()
        self.ignore = False
        if self.recipients is None or self.mailfrom is None:
            self.ignore = True
            return

        self.ctx = ctx
        self.cache = None
        if cache is not None:
            self.cache = weakref.ref(cache)
        self.repo = repo
        self.msg = MIMEMultipart()
        self.msg['Subject'] = '%s: bigitr error report' % repo
        self.msg['From'] = self.mailfrom
        self.msg['To'] = ', '.join(self.recipients)
        self.msg.preamble = 'Bigitr error report for repository %s' % repo

    @staticmethod
    def _filename(desc):
        desc = '_'.join(x for x in desc.split())
        desc = ''.join(x for x in desc if x.isalnum() or x == '_')
        return desc + '.txt'

    @ifEmail
    def addAttachment(self, text, desc):
        msg = MIMEText(text)
        msg.add_header('Content-Disposition',
                       'attachment',
                       filename=self._filename(desc))
        self.msg.attach(msg)

    @ifEmail
    def addOutput(self, command, stdout, stderr):
        self.addAttachment(stderr, 'errors from ' + command)
        self.addAttachment(stdout, 'output from ' + command)

    @ifEmail
    def send(self, allout, allerr):
        # send email only if an error has been attached
        if self.msg.get_payload():
            # First, attach the entire repository log; the individual
            # command messages will be embedded in it
            self.addAttachment(allerr, 'all errors')
            self.addAttachment(allout, 'all output')
            self._send()
        if self.cache and self.cache():
            del self.cache()[self.repo]

    def _send(self):
        s = smtplib.SMTP(self.ctx.getSmartHost())
        s.sendmail(self.ctx.getMailFrom(), self.recipients,
                   self.msg.as_string())
        s.quit()
Example #8
0
File: mail.py Project: mikjo/bigitr
class Email(object):
    def __init__(self, ctx, repo, cache):
        self.recipients = ctx.getEmail(repo)
        self.mailfrom = ctx.getMailFrom()
        self.ignore = False
        if self.recipients is None or self.mailfrom is None:
            self.ignore = True
            return

        self.ctx = ctx
        self.cache = None
        if cache is not None:
            self.cache = weakref.ref(cache)
        self.repo = repo
        self.msg = MIMEMultipart()
        self.msg['Subject'] = '%s: bigitr error report' % repo
        self.msg['From'] = self.mailfrom
        self.msg['To'] = ', '.join(self.recipients)
        self.msg.preamble = 'Bigitr error report for repository %s' % repo

    @staticmethod
    def _filename(desc):
        desc = '_'.join(x for x in desc.split())
        desc = ''.join(x for x in desc if x.isalnum() or x == '_')
        return desc + '.txt'

    @ifEmail
    def addAttachment(self, text, desc):
        msg = MIMEText(text)
        msg.add_header('Content-Disposition', 'attachment',
                       filename=self._filename(desc))
        self.msg.attach(msg)

    @ifEmail
    def addOutput(self, command, stdout, stderr):
        self.addAttachment(stderr, 'errors from ' + command)
        self.addAttachment(stdout, 'output from ' + command)

    @ifEmail
    def send(self, allout, allerr):
        # send email only if an error has been attached
        if self.msg.get_payload():
            # First, attach the entire repository log; the individual
            # command messages will be embedded in it
            self.addAttachment(allerr, 'all errors')
            self.addAttachment(allout, 'all output')
            self._send()
        if self.cache and self.cache():
            del self.cache()[self.repo]

    def _send(self):
        s = smtplib.SMTP(self.ctx.getSmartHost())
        s.sendmail(self.ctx.getMailFrom(),
                   self.recipients, self.msg.as_string())
        s.quit()
Example #9
0
def sendConfirm_thread(email, token):
    sender = validateAndGetField('EMAIL_SERVER')
    domain = validateAndGetField('EMAIL_PAGE_DOMAIN')
    subject = validateAndGetField('EMAIL_MAIL_SUBJECT')
    address = validateAndGetField('EMAIL_ADDRESS')
    port = validateAndGetField('EMAIL_PORT', default_type=int)
    password = validateAndGetField('EMAIL_PASSWORD')
    mail_plain = validateAndGetField('EMAIL_MAIL_PLAIN', raise_error=False)
    mail_html = validateAndGetField('EMAIL_MAIL_HTML', raise_error=False)

    if not (mail_plain or mail_html):
        raise NotAllFieldCompiled(
            f"Both EMAIL_MAIL_PLAIN and EMAIL_MAIL_HTML missing from settings.py, at least one of them is required."
        )

    domain += '/' if not domain.endswith('/') else ''

    msg = MIMEMultipart('alternative')
    msg['Subject'] = subject
    msg['From'] = sender
    msg['To'] = email

    from .views import verify
    link = ''
    for k, v in get_resolver(None).reverse_dict.items():
        if k is verify and v[0][0][1][0]:
            addr = str(v[0][0][0])
            link = domain + addr[0:addr.index('%')] + token

    if mail_plain:
        try:
            text = render_to_string(mail_plain, {'link': link})
            part1 = MIMEText(text, 'plain')
            msg.attach(part1)
        except AttributeError:
            pass

    if mail_html:
        try:
            html = render_to_string(mail_html, {'link': link})
            part2 = MIMEText(html, 'html')
            msg.attach(part2)
        except AttributeError:
            pass

    if not msg.get_payload():
        raise EmailTemplateNotFound('No email template found')

    server = SMTP(sender, port)
    server.starttls()
    server.login(address, password)
    server.sendmail(sender, email, msg.as_string())
    server.quit()
    def test_add_one_image_file_check_fields(self):
        """ message payload must have a image header  """
        email_builder = EmailBuilder("localhost", 8000, "sender_email", "receiver_email")
        message = MIMEMultipart()
        email_builder._add_image([b'01'], message)
        base = message.get_payload()[0]
        base_str = base.as_string()

        self.assertTrue('image/png' in base_str)
        self.assertTrue('filename="chart-image0.png"' in base_str)
        self.assertTrue('X-Attachment-Id: 0' in base_str)
        self.assertTrue('Content-ID: <0>' in base_str)
Example #11
0
 def parser_content(self, msg: MIMEMultipart) -> str:
     text_content = ''
     if self.len_string > 0:
         content = msg.get_payload()
         content_charset = content[0].get_content_charset()  # 获得内容编码格式
         text = content[0].as_string().split('base64')[-1]
         try:
             text_content = base64.b64decode(text).decode(content_charset)
         except Exception as err:
             logging.error(err)
         return text_content
     return text_content
Example #12
0
class ShinyMail(object):
    """ShinyMail constructs and sends emails."""
    def __init__(self, to, subject, message='', from_addr=None):
        """Initialize our mail object.
        
        to - a list of email addresses
        subject - a string containing the email subject
        message - a string containing the body of the email message (optional)
        from_addr - a string containing the from address (optional, will be
        replaced with EMAIL_HOST_USER from the shinymud config file if not given)
        """
        self.email = MIMEMultipart()
        self.email['Subject'] = subject
        self.email['To'] = ', '.join(to)
        self.email['From'] = from_addr or EMAIL_HOST_USER
        self.message = message
        self.files = []

    def attach_text_file(self, filename, content):
        """Attach a text file to this email.
        """
        msg = MIMEText(content)
        msg.add_header('Content-Disposition', 'attachment', filename=filename)
        self.files.append(msg)

    def send(self):
        """Actually send an email.
        """
        self._construct_email()
        con = smtplib.SMTP(EMAIL_HOST, EMAIL_PORT)
        con.set_debuglevel(1)
        if EMAIL_USE_TLS:
            con.starttls()
        if EMAIL_HOST_USER and EMAIL_HOST_PASSWORD:
            # Don't bother logging in if USER and PASS don't exist
            con.login(EMAIL_HOST_USER, EMAIL_HOST_PASSWORD)
        con.sendmail(self.email['From'], self.email['To'],
                     self.email.as_string())
        con.quit()

    def _construct_email(self):
        """Construct the email in a sensible order.
        
        Make sure the message text comes before any extra attachments.
        """
        if self.message:
            self.email.attach(MIMEText(self.message))
        for f in self.files:
            self.email.attach(f)
        if not self.email.get_payload():
            # Don't let people send blank emails. That's mean.
            raise Exception("You can't send an email without any content!")
Example #13
0
class ShinyMail(object):
    """ShinyMail constructs and sends emails."""
    
    def __init__(self, to, subject, message='', from_addr=None):
        """Initialize our mail object.
        
        to - a list of email addresses
        subject - a string containing the email subject
        message - a string containing the body of the email message (optional)
        from_addr - a string containing the from address (optional, will be
        replaced with EMAIL_HOST_USER from the shinymud config file if not given)
        """
        self.email = MIMEMultipart()
        self.email['Subject'] = subject
        self.email['To'] = ', '.join(to)
        self.email['From'] = from_addr or EMAIL_HOST_USER
        self.message = message
        self.files = []
    
    def attach_text_file(self, filename, content):
        """Attach a text file to this email.
        """
        msg = MIMEText(content)
        msg.add_header('Content-Disposition', 'attachment', filename=filename)
        self.files.append(msg)
    
    def send(self):
        """Actually send an email.
        """
        self._construct_email()
        con = smtplib.SMTP(EMAIL_HOST, EMAIL_PORT)
        con.set_debuglevel(1)
        if EMAIL_USE_TLS:
            con.starttls()
        if EMAIL_HOST_USER and EMAIL_HOST_PASSWORD:
            # Don't bother logging in if USER and PASS don't exist
            con.login(EMAIL_HOST_USER, EMAIL_HOST_PASSWORD)
        con.sendmail(self.email['From'], self.email['To'], self.email.as_string())
        con.quit()
    
    def _construct_email(self):
        """Construct the email in a sensible order.
        
        Make sure the message text comes before any extra attachments.
        """
        if self.message:
            self.email.attach(MIMEText(self.message))
        for f in self.files:
            self.email.attach(f)
        if not self.email.get_payload():
            # Don't let people send blank emails. That's mean.
            raise Exception("You can't send an email without any content!")
Example #14
0
    def test_add_attachement_no_ctype_no_encoding_compressed(self):
        config = EmailConfiguration()

        sender = MockEmailSender(config, mock_sender=MockSMTPServer("127.0.0.1", 80))

        msg = MIMEMultipart()

        attachment = os.path.dirname(__file__) + os.sep + "something.zip"

        sender._add_attachement(msg, attachment, ctype=None, encoding=None)

        self.assertEquals([('Content-Type', 'multipart/mixed'), ('MIME-Version', '1.0')], msg.items())
        self.assertEquals(1, len(msg.get_payload()))
Example #15
0
    def test_add_attachement_ctype_ecoding(self):
        config = EmailConfiguration()

        sender = MockEmailSender(config, mock_sender=MockSMTPServer("127.0.0.1", 80))

        msg = MIMEMultipart()

        attachment = os.path.dirname(__file__) + os.sep + "test.txt"

        sender._add_attachement(msg, attachment, ctype='text/plain', encoding="utf-8")

        self.assertEquals([('Content-Type', 'multipart/mixed'), ('MIME-Version', '1.0')], msg.items())
        self.assertEquals(1, len(msg.get_payload()))
Example #16
0
def sendConfirm_thread(email, token):
    from .models import User
    try:
        sender = settings.EMAIL_SERVER
        domain = settings.EMAIL_PAGE_DOMAIN
        subject = settings.EMAIL_MAIL_SUBJECT
        address = settings.EMAIL_ADDRESS
        port = settings.EMAIL_PORT
        password = settings.EMAIL_PASSWORD
    except AttributeError:
        raise NotAllFieldCompiled('Compile all the fields in the settings')

    domain += '/' if not domain.endswith('/') else ''

    msg = MIMEMultipart('alternative')
    msg['Subject'] = subject
    msg['From'] = sender
    msg['To'] = email

    link = ''
    for k, v in get_resolver(None).reverse_dict.items():
        if k is verify and v[0][0][1][0]:
            addr = str(v[0][0][0])
            link = domain + addr[0: addr.index('%')] + token

    try:
        plain = settings.EMAIL_MAIL_PLAIN
        text = render_to_string(plain, {'link': link})
        part1 = MIMEText(text, 'plain')
        msg.attach(part1)
    except AttributeError:
        pass
    try:
        html = settings.EMAIL_MAIL_HTML
        html = render_to_string(html, {'link': link})
        part2 = MIMEText(html, 'html')
        msg.attach(part2)
    except AttributeError:
        pass

    if not msg.get_payload():
        User.objects.get(email_token=token).delete()
        raise EmailTemplateNotFound('No email template found')

    server = SMTP(sender, port)
    server.starttls()
    server.login(address, password)
    server.sendmail(sender, email, msg.as_string())
    server.quit()
Example #17
0
def apply_mtom(headers, envelope, params, paramvals):
    '''
    Apply MTOM to a SOAP envelope, separating attachments into a
    MIME multipart message.

    References:
    XOP     http://www.w3.org/TR/xop10/
    MTOM    http://www.w3.org/TR/soap12-mtom/
            http://www.w3.org/Submission/soap11mtom10/

    @param headers   Headers dictionary of the SOAP message that would
                     originally be sent.
    @param envelope  SOAP envelope string that would have originally been sent.
    @param params    params attribute from the Message object used for the SOAP
    @param paramvals values of the params, passed to Message.to_xml
    @return          tuple of length 2 with dictionary of headers and
                     string of body that can be sent with HTTPConnection
    '''

    # grab the XML element of the message in the SOAP body
    soapmsg = StringIO(envelope)
    soaptree = ElementTree.parse(soapmsg)
    soapns = soaptree.getroot().tag.split('}')[0].strip('{')
    soapbody = soaptree.getroot().find("{%s}Body" % soapns)
    message = None
    for child in list(soapbody):
        if child.tag != "%sFault" % (soapns, ):
            message = child
            break

    # Get additional parameters from original Content-Type
    ctarray = []
    for n, v in headers.items():
        if n.lower() == 'content-type':
            ctarray = v.split(';')
            break
    roottype = ctarray[0].strip()
    rootparams = {}
    for ctparam in ctarray[1:]:
        n, v = ctparam.strip().split('=')
        rootparams[n] = v.strip("\"'")

    # Set up initial MIME parts
    mtompkg = MIMEMultipart('related',
        boundary='?//<><>soaplib_MIME_boundary<>')
    rootpkg = None
    try:
        rootpkg = MIMEApplication(envelope, 'xop+xml', encode_7or8bit)
    except NameError:
        rootpkg = MIMENonMultipart("application", "xop+xml")
        rootpkg.set_payload(envelope)
        encode_7or8bit(rootpkg)

    # Set up multipart headers.
    del(mtompkg['mime-version'])
    mtompkg.set_param('start-info', roottype)
    mtompkg.set_param('start', '<soaplibEnvelope>')
    if 'SOAPAction' in headers:
        mtompkg.add_header('SOAPAction', headers.get('SOAPAction'))

    # Set up root SOAP part headers.
    del(rootpkg['mime-version'])
    rootpkg.add_header('Content-ID', '<soaplibEnvelope>')
    for n, v in rootparams.items():
        rootpkg.set_param(n, v)
    rootpkg.set_param('type', roottype)

    mtompkg.attach(rootpkg)

    # Extract attachments from SOAP envelope.
    for i in range(len(params)):
        name, typ = params[i]
        if typ == Attachment:
            id = "soaplibAttachment_%s" % (len(mtompkg.get_payload()), )
            param = message[i]
            param.text = ""
            incl = create_xml_subelement(param,
                "{http://www.w3.org/2004/08/xop/include}Include")
            incl.attrib["href"] = "cid:%s" % id
            if paramvals[i].fileName and not paramvals[i].data:
                paramvals[i].load_from_file()
            data = paramvals[i].data
            attachment = None
            try:
                attachment = MIMEApplication(data, _encoder=encode_7or8bit)
            except NameError:
                attachment = MIMENonMultipart("application", "octet-stream")
                attachment.set_payload(data)
                encode_7or8bit(attachment)
            del(attachment['mime-version'])
            attachment.add_header('Content-ID', '<%s>' % (id, ))
            mtompkg.attach(attachment)

    # Update SOAP envelope.
    soapmsg.close()
    soapmsg = StringIO()
    soaptree.write(soapmsg)
    rootpkg.set_payload(soapmsg.getvalue())
    soapmsg.close()

    # extract body string from MIMEMultipart message
    bound = '--%s' % (mtompkg.get_boundary(), )
    marray = mtompkg.as_string().split(bound)
    mtombody = bound
    mtombody += bound.join(marray[1:])

    # set Content-Length
    mtompkg.add_header("Content-Length", str(len(mtombody)))

    # extract dictionary of headers from MIMEMultipart message
    mtomheaders = {}
    for name, value in mtompkg.items():
        mtomheaders[name] = value

    if len(mtompkg.get_payload()) <= 1:
        return (headers, envelope)

    return (mtomheaders, mtombody)
Example #18
0
def apply_mtom(headers, envelope, params, paramvals):
    """Apply MTOM to a SOAP envelope, separating attachments into a
    MIME multipart message.

    Returns a tuple of length 2 with dictionary of headers and string of body
    that can be sent with HTTPConnection

    References:
    XOP     http://www.w3.org/TR/xop10/
    MTOM    http://www.w3.org/TR/soap12-mtom/
            http://www.w3.org/Submission/soap11mtom10/

    :param headers   Headers dictionary of the SOAP message that would
                     originally be sent.
    :param envelope  Iterable containing SOAP envelope string that would have
                     originally been sent.
    :param params    params attribute from the Message object used for the SOAP
    :param paramvals values of the params, passed to Message.to_parent
    """

    # grab the XML element of the message in the SOAP body
    envelope = ''.join(envelope)

    soaptree = etree.fromstring(envelope)
    soapbody = soaptree.find("{%s}Body" % _ns_soap_env)

    message = None
    for child in list(soapbody):
        if child.tag == ("{%s}Fault" % _ns_soap_env):
            return headers, envelope
        else:
            message = child
            break

    # Get additional parameters from original Content-Type
    ctarray = []
    for n, v in headers.items():
        if n.lower() == 'content-type':
            ctarray = v.split(';')
            break

    roottype = ctarray[0].strip()
    rootparams = {}
    for ctparam in ctarray[1:]:
        n, v = ctparam.strip().split('=')
        rootparams[n] = v.strip("\"'")

    # Set up initial MIME parts.
    mtompkg = MIMEMultipart('related', boundary='?//<><>spyne_MIME_boundary<>')
    rootpkg = MIMEApplication(envelope, 'xop+xml', encode_7or8bit)

    # Set up multipart headers.
    del mtompkg['mime-version']
    mtompkg.set_param('start-info', roottype)
    mtompkg.set_param('start', '<spyneEnvelope>')
    if 'SOAPAction' in headers:
        mtompkg.add_header('SOAPAction', headers.get('SOAPAction'))

    # Set up root SOAP part headers.
    del rootpkg['mime-version']

    rootpkg.add_header('Content-ID', '<spyneEnvelope>')

    for n, v in rootparams.items():
        rootpkg.set_param(n, v)

    rootpkg.set_param('type', roottype)

    mtompkg.attach(rootpkg)

    # Extract attachments from SOAP envelope.
    for i in range(len(params)):
        name, typ = params[i]

        if issubclass(typ, (ByteArray, File)):
            id = "SpyneAttachment_%s" % (len(mtompkg.get_payload()), )

            param = message[i]
            param.text = ""

            incl = etree.SubElement(param, "{%s}Include" % _ns_xop)
            incl.attrib["href"] = "cid:%s" % id

            if paramvals[i].fileName and not paramvals[i].data:
                paramvals[i].load_from_file()

            if issubclass(type, File):
                data = paramvals[i].data
            else:
                data = ''.join(paramvals[i])

            attachment = MIMEApplication(data, _encoder=encode_7or8bit)

            del attachment['mime-version']

            attachment.add_header('Content-ID', '<%s>' % (id, ))
            mtompkg.attach(attachment)

    # Update SOAP envelope.
    rootpkg.set_payload(etree.tostring(soaptree))

    # extract body string from MIMEMultipart message
    bound = '--%s' % (mtompkg.get_boundary(), )
    marray = mtompkg.as_string().split(bound)
    mtombody = bound
    mtombody += bound.join(marray[1:])

    # set Content-Length
    mtompkg.add_header("Content-Length", str(len(mtombody)))

    # extract dictionary of headers from MIMEMultipart message
    mtomheaders = {}
    for name, value in mtompkg.items():
        mtomheaders[name] = value

    if len(mtompkg.get_payload()) <= 1:
        return headers, envelope

    return mtomheaders, [mtombody]
Example #19
0
    def _prepare_message(self, addresses, subject, contents, attachments, headers):
        """ Prepare a MIME message """
        if self.is_closed:
            raise YagConnectionClosed('Login required again')
        if isinstance(contents, text_type):
            contents = [contents]
        if isinstance(attachments, text_type):
            attachments = [attachments]

        # merge contents and attachments for now.
        if attachments is not None:
            for a in attachments:
                if not os.path.isfile(a):
                    raise TypeError("'{0}' is not a valid filepath".format(a))
            contents = attachments if contents is None else contents + attachments

        has_included_images, content_objects = self._prepare_contents(contents)
        msg = MIMEMultipart()
        if headers is not None:
            # Strangely, msg does not have an update method, so then manually.
            for k, v in headers.items():
                msg[k] = v

        msg_alternative = MIMEMultipart('alternative')
        msg_related = MIMEMultipart('related')
        msg_related.attach("-- HTML goes here --")
        msg.attach(msg_alternative)
        self._add_subject(msg, subject)
        self._add_recipients_headers(msg, addresses)
        htmlstr = ''
        altstr = []
        if has_included_images:
            msg.preamble = "This message is best displayed using a MIME capable email reader."

        if contents is not None:
            for content_object, content_string in zip(content_objects,
                                                      contents):
                if content_object['main_type'] == 'image':
                    # all image objects need base64 encoding, so do it now
                    email.encoders.encode_base64(content_object['mime_object'])
                    # aliased image {'path' : 'alias'}
                    if isinstance(content_string, dict) and len(content_string) == 1:
                        for key in content_string:
                            hashed_ref = str(abs(hash(key)))
                            alias = content_string[key]
                        # pylint: disable=undefined-loop-variable
                        content_string = key
                    else:

                        alias = os.path.basename(str(content_string))
                        hashed_ref = str(abs(hash(alias)))

                    # TODO: I should probably remove inline now that there is "attachments"
                    # if string is `inline`, inline, else, attach
                    # pylint: disable=unidiomatic-typecheck
                    if type(content_string) == inline:
                        htmlstr += '<img src="cid:{0}" title="{1}"/>'.format(hashed_ref, alias)
                        content_object['mime_object'].add_header(
                            'Content-ID', '<{0}>'.format(hashed_ref))
                        altstr.append('-- img {0} should be here -- '.format(alias))
                        # inline images should be in related MIME block
                        msg_related.attach(content_object['mime_object'])
                    else:
                        # non-inline images get attached like any other attachment
                        msg.attach(content_object['mime_object'])

                else:
                    if content_object['encoding'] == 'base64':
                        email.encoders.encode_base64(content_object['mime_object'])
                        msg.attach(content_object['mime_object'])
                    else:
                        content_string = content_string.replace('\n', '<br>')
                        try:
                            htmlstr += '<div>{0}</div>'.format(content_string)
                        except UnicodeEncodeError:
                            htmlstr += u'<div>{0}</div>'.format(content_string)
                        altstr.append(content_string)

        msg_related.get_payload()[0] = MIMEText(htmlstr, 'html', _charset=self.encoding)
        msg_alternative.attach(MIMEText('\n'.join(altstr), _charset=self.encoding))
        msg_alternative.attach(msg_related)
        return msg
Example #20
0
def prepare_message(user,
                    useralias,
                    addresses,
                    subject,
                    contents,
                    attachments,
                    headers,
                    encoding,
                    newline_to_break=True):
    # check if closed!!!!!! XXX
    """ Prepare a MIME message """
    if isinstance(contents, text_type):
        contents = [contents]
    if isinstance(attachments, text_type):
        attachments = [attachments]

    # merge contents and attachments for now.
    if attachments is not None:
        for a in attachments:
            if not os.path.isfile(a):
                raise TypeError("'{0}' is not a valid filepath".format(a))
        contents = attachments if contents is None else contents + attachments

    has_included_images, content_objects = prepare_contents(contents, encoding)
    msg = MIMEMultipart()
    if headers is not None:
        # Strangely, msg does not have an update method, so then manually.
        for k, v in headers.items():
            msg[k] = v
    if headers is None or "Date" not in headers:
        msg["Date"] = formatdate()

    msg_alternative = MIMEMultipart("alternative")
    msg_related = MIMEMultipart("related")
    msg_related.attach("-- HTML goes here --")
    msg.attach(msg_alternative)
    add_subject(msg, subject)
    add_recipients_headers(user, useralias, msg, addresses)
    htmlstr = ""
    altstr = []
    if has_included_images:
        msg.preamble = "This message is best displayed using a MIME capable email reader."

    if contents is not None:
        for content_object, content_string in zip(content_objects, contents):
            if content_object["main_type"] == "image":
                # all image objects need base64 encoding, so do it now
                email.encoders.encode_base64(content_object["mime_object"])
                # aliased image {'path' : 'alias'}
                if isinstance(content_string,
                              dict) and len(content_string) == 1:
                    for key in content_string:
                        hashed_ref = str(abs(hash(key)))
                        alias = content_string[key]
                    # pylint: disable=undefined-loop-variable
                    content_string = key
                else:
                    alias = os.path.basename(str(content_string))
                    hashed_ref = str(abs(hash(alias)))

                # TODO: I should probably remove inline now that there is "attachments"
                # if string is `inline`, inline, else, attach
                # pylint: disable=unidiomatic-typecheck
                if type(content_string) == inline:
                    htmlstr += '<img src="cid:{0}" title="{1}"/>'.format(
                        hashed_ref, alias)
                    content_object["mime_object"].add_header(
                        "Content-ID", "<{0}>".format(hashed_ref))
                    altstr.append(
                        "-- img {0} should be here -- ".format(alias))
                    # inline images should be in related MIME block
                    msg_related.attach(content_object["mime_object"])
                else:
                    # non-inline images get attached like any other attachment
                    msg.attach(content_object["mime_object"])

            else:
                if content_object["encoding"] == "base64":
                    email.encoders.encode_base64(content_object["mime_object"])
                    msg.attach(content_object["mime_object"])
                elif content_object["sub_type"] not in ["html", "plain"]:
                    msg.attach(content_object["mime_object"])
                else:
                    if newline_to_break:
                        content_string = content_string.replace("\n", "<br>")
                    try:
                        htmlstr += "<div>{0}</div>".format(content_string)
                    except UnicodeEncodeError:
                        htmlstr += u"<div>{0}</div>".format(content_string)
                    altstr.append(content_string)

    msg_related.get_payload()[0] = MIMEText(htmlstr, "html", _charset=encoding)
    msg_alternative.attach(MIMEText("\n".join(altstr), _charset=encoding))
    msg_alternative.attach(msg_related)
    return msg
Example #21
0
 def _decode_attachment(attachment_part: MIMEMultipart) -> bytes:
     return attachment_part.get_payload(decode=True)
Example #22
0
def prepare_message(user, useralias, addresses, subject, contents, attachments, headers, encoding, newline_to_break=True):
    # check if closed!!!!!! XXX
    """ Prepare a MIME message """
    if isinstance(contents, text_type):
        contents = [contents]
    if isinstance(attachments, text_type):
        attachments = [attachments]

    # merge contents and attachments for now.
    if attachments is not None:
        for a in attachments:
            if not os.path.isfile(a):
                raise TypeError("'{0}' is not a valid filepath".format(a))
        contents = attachments if contents is None else contents + attachments

    has_included_images, content_objects = prepare_contents(contents, encoding)
    msg = MIMEMultipart()
    if headers is not None:
        # Strangely, msg does not have an update method, so then manually.
        for k, v in headers.items():
            msg[k] = v
    if headers is None or "Date" not in headers:
        msg["Date"] = formatdate()

    msg_alternative = MIMEMultipart("alternative")
    msg_related = MIMEMultipart("related")
    msg_related.attach("-- HTML goes here --")
    msg.attach(msg_alternative)
    add_subject(msg, subject)
    add_recipients_headers(user, useralias, msg, addresses)
    htmlstr = ""
    altstr = []
    if has_included_images:
        msg.preamble = "This message is best displayed using a MIME capable email reader."

    if contents is not None:
        for content_object, content_string in zip(content_objects, contents):
            if content_object["main_type"] == "image":
                # all image objects need base64 encoding, so do it now
                email.encoders.encode_base64(content_object["mime_object"])
                # aliased image {'path' : 'alias'}
                if isinstance(content_string, dict) and len(content_string) == 1:
                    for key in content_string:
                        hashed_ref = str(abs(hash(key)))
                        alias = content_string[key]
                    # pylint: disable=undefined-loop-variable
                    content_string = key
                else:
                    alias = os.path.basename(str(content_string))
                    hashed_ref = str(abs(hash(alias)))

                # TODO: I should probably remove inline now that there is "attachments"
                # if string is `inline`, inline, else, attach
                # pylint: disable=unidiomatic-typecheck
                if type(content_string) == inline:
                    htmlstr += '<img src="cid:{0}" title="{1}"/>'.format(hashed_ref, alias)
                    content_object["mime_object"].add_header(
                        "Content-ID", "<{0}>".format(hashed_ref)
                    )
                    altstr.append("-- img {0} should be here -- ".format(alias))
                    # inline images should be in related MIME block
                    msg_related.attach(content_object["mime_object"])
                else:
                    # non-inline images get attached like any other attachment
                    msg.attach(content_object["mime_object"])

            else:
                if content_object["encoding"] == "base64":
                    email.encoders.encode_base64(content_object["mime_object"])
                    msg.attach(content_object["mime_object"])
                elif content_object["sub_type"] not in ["html", "plain"]:
                    msg.attach(content_object["mime_object"])
                else:
                    if newline_to_break:
                        content_string = content_string.replace("\n", "<br>")
                    try:
                        htmlstr += "<div>{0}</div>".format(content_string)
                    except UnicodeEncodeError:
                        htmlstr += u"<div>{0}</div>".format(content_string)
                    altstr.append(content_string)

    msg_related.get_payload()[0] = MIMEText(htmlstr, "html", _charset=encoding)
    msg_alternative.attach(MIMEText("\n".join(altstr), _charset=encoding))
    msg_alternative.attach(msg_related)
    return msg
Example #23
0
class HttpMessage(object):
    '''
    generate and parse message in MIME multipart/related (RFC2387) structure.
    Its core variable is a MIMEMultipart Object
    '''
    DEFAULT_MAIN_CONTENT_ID_HEADER_VALUE = 'Main'

    def __init__(self, multipart = None):
        '''
        If parameter 'multipart' is None, then create an empty MIMEMultipart, whose body parts
        need to be added by invoking methods addMainpart() and add().
        Otherwise reuse the exising multipart Object (this has been used by parseMIMEmessage() method.)
        '''
        if multipart==None:
            self.multipart = MIMEMultipart('related')
        else:
            self.multipart = multipart
         
    def addMainpart(self, mainPartString, mainPartContentType='text/turtle'):
        self.multipart.set_param('type', mainPartContentType)
        self.multipart.set_param('start', self.DEFAULT_MAIN_CONTENT_ID_HEADER_VALUE)
        
        self.add(self.DEFAULT_MAIN_CONTENT_ID_HEADER_VALUE, mainPartString, mainPartContentType)
    
    def add(self, partId, partString, partContentType='text/turtle'):
        [mainType, subType]=partContentType.split('/')
        if mainType.lower()=='text':
            part = MIMEText(partString, subType)
        elif mainType.lower() == 'application':
            part = MIMEApplication(partString, subType, email.encoders.encode_7or8bit)
        
        if part is not None:
            part.add_header('Content-ID', partId)
            #mime package automatically add 'Content-Transfer-Encoding' header. We do not need it.
            #part.__delitem__('Content-Transfer-Encoding')
            self.multipart.attach(part)
    
    def getBody(self):
        '''
        print out the whole multipart message as a String (including Content-Type header)
        @return string
        '''       
        return self.multipart.as_string()
         
    def getParts(self):
        '''
        return the body parts as a list of MIME Object. Each body part includes body string and headers
        '''
        payload = self.multipart.get_payload()
        return payload
    
    def getPart(self, partId):
        '''
        return the body part whose Content-ID value is partId. Return only the body part string, no headers
        @return: string
        '''
        payload = self.multipart.get_payload()
        for part in payload:
            if partId == part.get('Content-ID'):
                return part.get_payload()
        
        return None
    
    def getMainPart(self):
        '''
        return the body part of "Main" part. No headers.
        '''
        return self.getPart(self.DEFAULT_MAIN_CONTENT_ID_HEADER_VALUE)
    
    def getNonMainPartsAsDict(self):
        '''
        return all those non "Main" parts as a dictionary (key is Content-ID, value is the body string). No headers
        '''
        rt = {}
        payload = self.multipart.get_payload()
        for part in payload:
            if part.get('Content-ID')!= self.DEFAULT_MAIN_CONTENT_ID_HEADER_VALUE:
                rt[part.get('Content-ID')] = part.get_payload()
        
        return rt
    
    def getContentType(self):
        '''
        return the Content-Type header value, including its parameters.
        '''
        return self.multipart.get('Content-Type')
    
    def isMultipart(self):
        return self.multipart.is_multipart()
    
    def asString(self):
        return self.getBody()
Example #24
0
def apply_mtom(headers, envelope, params, paramvals):
    """
    Apply MTOM to a SOAP envelope, separating attachments into a
    MIME multipart message.

    References:
    XOP     http://www.w3.org/TR/xop10/
    MTOM    http://www.w3.org/TR/soap12-mtom/
            http://www.w3.org/Submission/soap11mtom10/

    @param headers   Headers dictionary of the SOAP message that would
                     originally be sent.
    @param envelope  SOAP envelope string that would have originally been sent.
    @param params    params attribute from the Message object used for the SOAP
    @param paramvals values of the params, passed to Message.to_xml
    @return          tuple of length 2 with dictionary of headers and
                     string of body that can be sent with HTTPConnection
    """

    # grab the XML element of the message in the SOAP body
    soaptree = etree.fromstring(envelope)
    soapbody = soaptree.find("{%s}Body" % soaplib.ns_soap_env)

    message = None
    for child in list(soapbody):
        if child.tag != "%sFault" % (soaplib.ns_soap_env,):
            message = child
            break

    # Get additional parameters from original Content-Type
    ctarray = []
    for n, v in headers.items():
        if n.lower() == "content-type":
            ctarray = v.split(";")
            break
    roottype = ctarray[0].strip()
    rootparams = {}
    for ctparam in ctarray[1:]:
        n, v = ctparam.strip().split("=")
        rootparams[n] = v.strip("\"'")

    # Set up initial MIME parts.
    mtompkg = MIMEMultipart("related", boundary="?//<><>soaplib_MIME_boundary<>")
    rootpkg = None
    try:
        rootpkg = MIMEApplication(envelope, "xop+xml", encode_7or8bit)
    except NameError:
        rootpkg = MIMENonMultipart("application", "xop+xml")
        rootpkg.set_payload(envelope)
        encode_7or8bit(rootpkg)

    # Set up multipart headers.
    del (mtompkg["mime-version"])
    mtompkg.set_param("start-info", roottype)
    mtompkg.set_param("start", "<soaplibEnvelope>")
    if "SOAPAction" in headers:
        mtompkg.add_header("SOAPAction", headers.get("SOAPAction"))

    # Set up root SOAP part headers.
    del (rootpkg["mime-version"])

    rootpkg.add_header("Content-ID", "<soaplibEnvelope>")

    for n, v in rootparams.items():
        rootpkg.set_param(n, v)

    rootpkg.set_param("type", roottype)

    mtompkg.attach(rootpkg)

    # Extract attachments from SOAP envelope.
    for i in range(len(params)):
        name, typ = params[i]

        if typ == Attachment:
            id = "soaplibAttachment_%s" % (len(mtompkg.get_payload()),)

            param = message[i]
            param.text = ""

            incl = etree.SubElement(param, "{%s}Include" % soaplib.ns_xop)
            incl.attrib["href"] = "cid:%s" % id

            if paramvals[i].fileName and not paramvals[i].data:
                paramvals[i].load_from_file()

            data = paramvals[i].data
            attachment = None

            try:
                attachment = MIMEApplication(data, _encoder=encode_7or8bit)

            except NameError:
                attachment = MIMENonMultipart("application", "octet-stream")
                attachment.set_payload(data)
                encode_7or8bit(attachment)

            del (attachment["mime-version"])

            attachment.add_header("Content-ID", "<%s>" % (id,))
            mtompkg.attach(attachment)

    # Update SOAP envelope.
    rootpkg.set_payload(etree.tostring(soaptree))

    # extract body string from MIMEMultipart message
    bound = "--%s" % (mtompkg.get_boundary(),)
    marray = mtompkg.as_string().split(bound)
    mtombody = bound
    mtombody += bound.join(marray[1:])

    # set Content-Length
    mtompkg.add_header("Content-Length", str(len(mtombody)))

    # extract dictionary of headers from MIMEMultipart message
    mtomheaders = {}
    for name, value in mtompkg.items():
        mtomheaders[name] = value

    if len(mtompkg.get_payload()) <= 1:
        return (headers, envelope)

    return (mtomheaders, mtombody)
Example #25
0
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart

msg = MIMEMultipart('alternative')

me = '*****@*****.**'
you = '*****@*****.**'
msgbody = 'This is the body of the error system, and a test.'
# me == the sender's email address
# you == the recipient's email address
msg['Subject'] = 'Error with your amazing software'
msg['From'] = me
msg['To'] = you

mimebody = MIMEText(msgbody, 'plain')
msg.attach(mimebody)
composed = str(msg)
msg.get_payload()
s = smtplib.SMTP('smtp.gmail.com', 587)
s.starttls()
s.login('*****@*****.**', 'password')
s.sendmail('*****@*****.**', '*****@*****.**', composed)

s.quit()
Example #26
0
File: mime.py Project: Bernie/spyne
def apply_mtom(headers, envelope, params, paramvals):
    '''Apply MTOM to a SOAP envelope, separating attachments into a
    MIME multipart message.

    Returns a tuple of length 2 with dictionary of headers and string of body
    that can be sent with HTTPConnection

    References:
    XOP     http://www.w3.org/TR/xop10/
    MTOM    http://www.w3.org/TR/soap12-mtom/
            http://www.w3.org/Submission/soap11mtom10/

    :param headers   Headers dictionary of the SOAP message that would
                     originally be sent.
    :param envelope  Iterable containing SOAP envelope string that would have
                     originally been sent.
    :param params    params attribute from the Message object used for the SOAP
    :param paramvals values of the params, passed to Message.to_parent_element
    '''

    # grab the XML element of the message in the SOAP body
    envelope = ''.join(envelope)

    soaptree = etree.fromstring(envelope)
    soapbody = soaptree.find("{%s}Body" % _ns_soap_env)

    message = None
    for child in list(soapbody):
        if child.tag == ("{%s}Fault" % _ns_soap_env):
            return (headers, envelope)
        else:
            message = child
            break

    # Get additional parameters from original Content-Type
    ctarray = []
    for n, v in headers.items():
        if n.lower() == 'content-type':
            ctarray = v.split(';')
            break

    roottype = ctarray[0].strip()
    rootparams = {}
    for ctparam in ctarray[1:]:
        n, v = ctparam.strip().split('=')
        rootparams[n] = v.strip("\"'")

    # Set up initial MIME parts.
    mtompkg = MIMEMultipart('related', boundary='?//<><>spyne_MIME_boundary<>')
    rootpkg = MIMEApplication(envelope, 'xop+xml', encode_7or8bit)

    # Set up multipart headers.
    del(mtompkg['mime-version'])
    mtompkg.set_param('start-info', roottype)
    mtompkg.set_param('start', '<spyneEnvelope>')
    if 'SOAPAction' in headers:
        mtompkg.add_header('SOAPAction', headers.get('SOAPAction'))

    # Set up root SOAP part headers.
    del(rootpkg['mime-version'])

    rootpkg.add_header('Content-ID', '<spyneEnvelope>')

    for n, v in rootparams.items():
        rootpkg.set_param(n, v)

    rootpkg.set_param('type', roottype)

    mtompkg.attach(rootpkg)

    # Extract attachments from SOAP envelope.
    for i in range(len(params)):
        name, typ = params[i]

        if typ in (ByteArray, Attachment):
            id = "spyneAttachment_%s" % (len(mtompkg.get_payload()), )

            param = message[i]
            param.text = ""

            incl = etree.SubElement(param, "{%s}Include" % _ns_xop)
            incl.attrib["href"] = "cid:%s" % id

            if paramvals[i].fileName and not paramvals[i].data:
                paramvals[i].load_from_file()

            if type == Attachment:
                data = paramvals[i].data
            else:
                data = ''.join(paramvals[i])
            attachment = None

            attachment = MIMEApplication(data, _encoder=encode_7or8bit)

            del(attachment['mime-version'])

            attachment.add_header('Content-ID', '<%s>' % (id, ))
            mtompkg.attach(attachment)

    # Update SOAP envelope.
    rootpkg.set_payload(etree.tostring(soaptree))

    # extract body string from MIMEMultipart message
    bound = '--%s' % (mtompkg.get_boundary(), )
    marray = mtompkg.as_string().split(bound)
    mtombody = bound
    mtombody += bound.join(marray[1:])

    # set Content-Length
    mtompkg.add_header("Content-Length", str(len(mtombody)))

    # extract dictionary of headers from MIMEMultipart message
    mtomheaders = {}
    for name, value in mtompkg.items():
        mtomheaders[name] = value

    if len(mtompkg.get_payload()) <= 1:
        return (headers, envelope)

    return (mtomheaders, [mtombody])
Example #27
0
File: soap.py Project: caot/soaplib
def apply_mtom(headers, envelope, params, paramvals):
    '''
    Apply MTOM to a SOAP envelope, separating attachments into a
    MIME multipart message.

    References:
    XOP     http://www.w3.org/TR/xop10/
    MTOM    http://www.w3.org/TR/soap12-mtom/
            http://www.w3.org/Submission/soap11mtom10/

    @param headers   Headers dictionary of the SOAP message that would
                     originally be sent.
    @param envelope  SOAP envelope string that would have originally been sent.
    @param params    params attribute from the Message object used for the SOAP
    @param paramvals values of the params, passed to Message.to_xml
    @return          tuple of length 2 with dictionary of headers and
                     string of body that can be sent with HTTPConnection
    '''

    # grab the XML element of the message in the SOAP body
    soapmsg = StringIO(envelope)
    soaptree = ElementTree.parse(soapmsg)
    soapns = soaptree.getroot().tag.split('}')[0].strip('{')
    soapbody = soaptree.getroot().find("{%s}Body" % soapns)
    message = None
    for child in list(soapbody):
        if child.tag != "%sFault" % (soapns, ):
            message = child
            break

    # Get additional parameters from original Content-Type
    ctarray = []
    for n, v in headers.items():
        if n.lower() == 'content-type':
            ctarray = v.split(';')
            break
    roottype = ctarray[0].strip()
    rootparams = {}
    for ctparam in ctarray[1:]:
        n, v = ctparam.strip().split('=')
        rootparams[n] = v.strip("\"'")

    # Set up initial MIME parts
    mtompkg = MIMEMultipart('related',
                            boundary='?//<><>soaplib_MIME_boundary<>')
    rootpkg = None
    try:
        rootpkg = MIMEApplication(envelope, 'xop+xml', encode_7or8bit)
    except NameError:
        rootpkg = MIMENonMultipart("application", "xop+xml")
        rootpkg.set_payload(envelope)
        encode_7or8bit(rootpkg)

    # Set up multipart headers.
    del (mtompkg['mime-version'])
    mtompkg.set_param('start-info', roottype)
    mtompkg.set_param('start', '<soaplibEnvelope>')
    if 'SOAPAction' in headers:
        mtompkg.add_header('SOAPAction', headers.get('SOAPAction'))

    # Set up root SOAP part headers.
    del (rootpkg['mime-version'])
    rootpkg.add_header('Content-ID', '<soaplibEnvelope>')
    for n, v in rootparams.items():
        rootpkg.set_param(n, v)
    rootpkg.set_param('type', roottype)

    mtompkg.attach(rootpkg)

    # Extract attachments from SOAP envelope.
    for i in range(len(params)):
        name, typ = params[i]
        if typ == Attachment:
            id = "soaplibAttachment_%s" % (len(mtompkg.get_payload()), )
            param = message[i]
            param.text = ""
            incl = create_xml_subelement(
                param, "{http://www.w3.org/2004/08/xop/include}Include")
            incl.attrib["href"] = "cid:%s" % id
            if paramvals[i].fileName and not paramvals[i].data:
                paramvals[i].load_from_file()
            data = paramvals[i].data
            attachment = None
            try:
                attachment = MIMEApplication(data, _encoder=encode_7or8bit)
            except NameError:
                attachment = MIMENonMultipart("application", "octet-stream")
                attachment.set_payload(data)
                encode_7or8bit(attachment)
            del (attachment['mime-version'])
            attachment.add_header('Content-ID', '<%s>' % (id, ))
            mtompkg.attach(attachment)

    # Update SOAP envelope.
    soapmsg.close()
    soapmsg = StringIO()
    soaptree.write(soapmsg)
    rootpkg.set_payload(soapmsg.getvalue())
    soapmsg.close()

    # extract body string from MIMEMultipart message
    bound = '--%s' % (mtompkg.get_boundary(), )
    marray = mtompkg.as_string().split(bound)
    mtombody = bound
    mtombody += bound.join(marray[1:])

    # set Content-Length
    mtompkg.add_header("Content-Length", str(len(mtombody)))

    # extract dictionary of headers from MIMEMultipart message
    mtomheaders = {}
    for name, value in mtompkg.items():
        mtomheaders[name] = value

    if len(mtompkg.get_payload()) <= 1:
        return (headers, envelope)

    return (mtomheaders, mtombody)
Example #28
0
def prepare_message(user, useralias, addresses, subject, contents, attachments,
                    encoding):
    """ Prepare a MIME message """
    if isinstance(contents, text_type):
        contents = [contents]

    if isinstance(attachments, text_type):
        attachments = [attachments]

    if attachments is not None:
        contents = attachments if contents is None else contents + attachments

    print('contents: {0}'.format(contents))
    has_included_images, content_objects = prepare_contents(contents, encoding)

    print('has_included_images={0}\ncontent_objects={1}'.format(
        has_included_images, content_objects))

    # mixed
    msg = MIMEMultipart()

    add_date(msg)

    add_subject(msg, subject)

    # 纯文本与超文本共存
    msg_alternative = MIMEMultipart("alternative")

    # 可以包含内嵌资源。
    msg_related = MIMEMultipart("related")
    msg_related.attach("-- HTML goes here --")

    msg.attach(msg_alternative)

    add_recipients_headers(user, useralias, msg, addresses)

    htmlstr = ""
    altstr = []

    if contents is not None:
        for content_object, content_string in zip(content_objects, contents):

            print('*****************t200:', content_object)
            if content_object["main_type"] == "image":
                pass
            else:
                if content_object["encoding"] == "base64":
                    email.encoders.encode_base64(content_object["mime_object"])
                    msg.attach(content_object["mime_object"])

                else:
                    content_string = content_string.replace("\n", "<br>")
                    try:
                        htmlstr += "<div>{0}</div>".format(content_string)
                    except UnicodeEncodeError:
                        htmlstr += u"<div>{0}</div>".format(content_string)
                    altstr.append(content_string)

    msg_related.get_payload()[0] = MIMEText(htmlstr, "html", _charset=encoding)
    msg_alternative.attach(MIMEText("\n".join(altstr), _charset=encoding))
    msg_alternative.attach(msg_related)

    return msg
Example #29
0
class ComposerPanel(wx.Panel):
	#TODO user RFC email header, add subject, multiprocess attachment
	"""Panel for mail composer"""
	def __init__(self, parent):
		wx.Panel.__init__(self, parent)

		#Message object
		self.msg = MIMEMultipart()
		self.payloadLs = self.msg.get_payload()
		self.bodyid = len(self.payloadLs) - 1

		#Create some sizer
		mainVSizer = wx.BoxSizer(wx.VERTICAL)
		buttonHSizer = wx.BoxSizer(wx.HORIZONTAL)
		recvHSizer = wx.BoxSizer(wx.HORIZONTAL)
		fromHSizer = wx.BoxSizer(wx.HORIZONTAL)
		subjectHSizer = wx.BoxSizer(wx.HORIZONTAL)
		attachHSizer = wx.BoxSizer(wx.HORIZONTAL)
		

		self.fromLbl = wx.StaticText(self, label="From:")
		fromHSizer.Add(self.fromLbl, 0, wx.EXPAND)
		##From text control
		self.fromTc = wx.TextCtrl(self, size=(-1,-1))
		fromHSizer.Add(self.fromTc, 1, wx.EXPAND)


		self.recvLbl = wx.StaticText(self, label="Recipients:")
		recvHSizer.Add(self.recvLbl, 0, wx.EXPAND)
		#Receivers text control
		self.recvTc = wx.TextCtrl(self, size=(-1, -1))
		recvHSizer.Add(self.recvTc, 1, wx.EXPAND)

		self.subjectLbl = wx.StaticText(self, label="Subject:")
		subjectHSizer.Add(self.subjectLbl, 0, wx.EXPAND)
		#Subject tc
		self.subjectTc = wx.TextCtrl(self, size=(-1, -1)) 
		subjectHSizer.Add(self.subjectTc, 1, wx.EXPAND)

		#Attach
		self.attachLbl = wx.StaticText(self, label='Attachment:')
		self.attachTc = wx.TextCtrl(self)
		self.attachBtn = wx.Button(self, label='Add')
		self.Bind(wx.EVT_BUTTON, self.AddClick, self.attachBtn)

		attachHSizer.Add(self.attachLbl, 0)
		attachHSizer.Add(self.attachTc, 1, wx.EXPAND)
		attachHSizer.Add(self.attachBtn, 0)

		#Content tc - multiline
		self.contentTc = wx.TextCtrl(self, style=wx.TE_MULTILINE)

		#buttons Clear - Send 
		self.clearBtn = wx.Button(self, label="Clear")
		self.Bind(wx.EVT_BUTTON, self.ClearClick, self.clearBtn)
		buttonHSizer.Add(self.clearBtn, 0)

		self.sendBtn = wx.Button(self, label="Send")
		self.Bind(wx.EVT_BUTTON, self.SendClick, self.sendBtn)
		buttonHSizer.Add(self.sendBtn, 0)

		mainVSizer.Add(fromHSizer, 0, wx.EXPAND)
		mainVSizer.Add(recvHSizer, 0, wx.EXPAND)
		mainVSizer.Add(subjectHSizer, 0, wx.EXPAND)
		mainVSizer.Add(attachHSizer, 0, wx.EXPAND)
		mainVSizer.Add(self.contentTc, 1, wx.EXPAND)
		mainVSizer.Add(buttonHSizer, 0, wx.ALL, 5)

		self.SetSizerAndFit(mainVSizer)



	def AddClick(self, event):
		"""Attach a file to email"""
		body = MIMEText(self.contentTc.GetValue())
		self.msg.attach(body)
		self.payloadLs = self.msg.get_payload()
		self.bodyid = len(self.payloadLs) - 1

		#Choose file
		self.dirname = ''
		dlg = wx.FileDialog(self, "Choose a file", self.dirname, "", "*.*", wx.OPEN)
		if dlg.ShowModal() == wx.ID_OK: #user cannot do anything on app util click ok or cancel
			#dlg.ShowModal() return ID of button pressed
			self.filename = dlg.GetFilename()
			self.dirname = dlg.GetDirectory()
			#f = open(os.path.join(self.dirname, self.filename), 'r')
			#TODO attach here
			att = attach.attachfile(os.path.join(self.dirname, self.filename), self.filename)
			self.msg.attach(att)
		dlg.Destroy()
		self.attachTc.AppendText(self.filename + ' ')

	def SendClick(self, event):
		"""Send mail """
		sender = self.fromTc.GetValue()
		recp = self.recvTc.GetValue()
		subj = self.subjectTc.GetValue()
		body = MIMEText(self.contentTc.GetValue())

		self.msg['Subject'] = subj
		self.msg['To'] = recp
		self.msg['From'] = sender
		self.msg.attach(body)

		if self.payloadLs:
			last = len(self.payloadLs) - 1
			self.payloadLs[self.bodyid] = self.payloadLs[-1]
			self.payloadLs.__delitem__(last)
			self.msg.set_payload(self.payloadLs)


		composed = self.msg.as_string()
		#TODO need a parser to parse email address to host address
		s = smtplib.SMTP('localhost')
		#TODO fix no rset bug
		s.sendmail(sender, recp, composed)
		#TODO change status bar if mail sented

	def ClearClick(self, event):
		"""Clear content control"""
		self.contentTc.Clear()
Example #30
0
        <th>Gb</th>
    </tr>
    {coordinfo}
    </table>
    </p>

    </body>
    </html>""".format(**kwargs)

    msg.attach(MIMEText(txt, 'html'))

    for fname in attachments or ():
        with open(fname, 'rb') as f:
            part = MIMEApplication(f.read(), 'pdf', Name=os.path.basename(fname))
        part['Content-Disposition'] = 'attachment; filename="{}"'.format(os.path.basename(fname).replace('_candidates_summary', ''))
        msg.attach(part)

    log("Sending email to: {}".format(to))
    smtp = smtplib.SMTP()
    smtp.connect()
    try:
        smtp.sendmail(frm, to, msg.as_string())
    except smtplib.SMTPSenderRefused:
        # assume attachments are too large
        # resend without attachments
        # first element of payload is main text, rest are attachments
        msg.set_payload(msg.get_payload()[0])
        smtp.sendmail(frm, to, msg.as_string())
        
    smtp.close()