def safe_fix_maintainer(content, fieldname): """Wrapper for fix_maintainer() to handle unicode and string argument. It verifies the content type and transform it in a unicode with guess() before call ascii_smash(). Then we can safely call fix_maintainer(). """ if type(content) != unicode: content = guess_encoding(content) content = ascii_smash(content) return fix_maintainer(content, fieldname)
def send_mail(spr, archive, to_addrs, subject, mail_text, dry_run, from_addr=None, bcc=None, changesfile_content=None, attach_changes=False, logger=None): """Send an email to to_addrs with the given text and subject. :param spr: The `ISourcePackageRelease` to be notified about. :param archive: The target `IArchive`. :param to_addrs: A list of email addresses to be used as recipients. Each email must be a valid ASCII str instance or a unicode one. :param subject: The email's subject. :param mail_text: The text body of the email. Unicode is preserved in the email. :param dry_run: Whether or not an email should actually be sent. But please note that this flag is (largely) ignored. :param from_addr: The email address to be used as the sender. Must be a valid ASCII str instance or a unicode one. Defaults to the email for config.uploader. :param bcc: Optional email Blind Carbon Copy address(es). :param param changesfile_content: The content of the actual changesfile. :param attach_changes: A flag governing whether the original changesfile content shall be attached to the email. """ extra_headers = {'X-Katie': 'Launchpad actually'} # Include the 'X-Launchpad-PPA' header for PPA upload notfications # containing the PPA owner name. if archive.is_ppa: extra_headers['X-Launchpad-PPA'] = get_ppa_reference(archive) # Include a 'X-Launchpad-Component' header with the component and # the section of the source package uploaded in order to facilitate # filtering on the part of the email recipients. if spr: xlp_component_header = 'component=%s, section=%s' % ( spr.component.name, spr.section.name) extra_headers['X-Launchpad-Component'] = xlp_component_header if from_addr is None: from_addr = format_address(config.uploader.default_sender_name, config.uploader.default_sender_address) # `sendmail`, despite handling unicode message bodies, can't # cope with non-ascii sender/recipient addresses, so ascii_smash # is used on all addresses. # All emails from here have a Bcc to the default recipient. bcc_text = format_address(config.uploader.default_recipient_name, config.uploader.default_recipient_address) if bcc: bcc_text = "%s, %s" % (bcc_text, bcc) extra_headers['Bcc'] = ascii_smash(bcc_text) recipients = ascii_smash(", ".join(to_addrs)) if isinstance(from_addr, unicode): # ascii_smash only works on unicode strings. from_addr = ascii_smash(from_addr) else: from_addr.encode('ascii') if dry_run and logger is not None: debug(logger, "Would have sent a mail:") else: debug(logger, "Sent a mail:") debug(logger, " Subject: %s" % subject) debug(logger, " Sender: %s" % from_addr) debug(logger, " Recipients: %s" % recipients) if 'Bcc' in extra_headers: debug(logger, " Bcc: %s" % extra_headers['Bcc']) debug(logger, " Body:") for line in mail_text.splitlines(): if isinstance(line, str): line = line.decode('utf-8', 'replace') debug(logger, line) if not dry_run: # Since we need to send the original changesfile as an # attachment the sendmail() method will be used as opposed to # simple_sendmail(). message = MIMEMultipart() message['from'] = from_addr message['subject'] = subject message['to'] = recipients # Set the extra headers if any are present. for key, value in extra_headers.iteritems(): message.add_header(key, value) # Add the email body. message.attach( MIMEText( sanitize_string(mail_text).encode('utf-8'), 'plain', 'utf-8')) if attach_changes: # Add the original changesfile as an attachment. if changesfile_content is not None: changesfile_text = sanitize_string(changesfile_content) else: changesfile_text = ("Sorry, changesfile not available.") attachment = MIMEText(changesfile_text.encode('utf-8'), 'plain', 'utf-8') attachment.add_header('Content-Disposition', 'attachment; filename="changesfile"') message.attach(attachment) # And finally send the message. sendmail(message)
def send_mail( spr, archive, to_addrs, subject, mail_text, dry_run, from_addr=None, bcc=None, changesfile_content=None, attach_changes=False, logger=None): """Send an email to to_addrs with the given text and subject. :param spr: The `ISourcePackageRelease` to be notified about. :param archive: The target `IArchive`. :param to_addrs: A list of email addresses to be used as recipients. Each email must be a valid ASCII str instance or a unicode one. :param subject: The email's subject. :param mail_text: The text body of the email. Unicode is preserved in the email. :param dry_run: Whether or not an email should actually be sent. But please note that this flag is (largely) ignored. :param from_addr: The email address to be used as the sender. Must be a valid ASCII str instance or a unicode one. Defaults to the email for config.uploader. :param bcc: Optional email Blind Carbon Copy address(es). :param param changesfile_content: The content of the actual changesfile. :param attach_changes: A flag governing whether the original changesfile content shall be attached to the email. """ extra_headers = {'X-Katie': 'Launchpad actually'} # Include the 'X-Launchpad-PPA' header for PPA upload notfications # containing the PPA owner name. if archive.is_ppa: extra_headers['X-Launchpad-PPA'] = get_ppa_reference(archive) # Include a 'X-Launchpad-Component' header with the component and # the section of the source package uploaded in order to facilitate # filtering on the part of the email recipients. if spr: xlp_component_header = 'component=%s, section=%s' % ( spr.component.name, spr.section.name) extra_headers['X-Launchpad-Component'] = xlp_component_header if from_addr is None: from_addr = format_address( config.uploader.default_sender_name, config.uploader.default_sender_address) # `sendmail`, despite handling unicode message bodies, can't # cope with non-ascii sender/recipient addresses, so ascii_smash # is used on all addresses. # All emails from here have a Bcc to the default recipient. bcc_text = format_address( config.uploader.default_recipient_name, config.uploader.default_recipient_address) if bcc: bcc_text = "%s, %s" % (bcc_text, bcc) extra_headers['Bcc'] = ascii_smash(bcc_text) recipients = ascii_smash(", ".join(to_addrs)) if isinstance(from_addr, unicode): # ascii_smash only works on unicode strings. from_addr = ascii_smash(from_addr) else: from_addr.encode('ascii') if dry_run and logger is not None: debug(logger, "Would have sent a mail:") else: debug(logger, "Sent a mail:") debug(logger, " Subject: %s" % subject) debug(logger, " Sender: %s" % from_addr) debug(logger, " Recipients: %s" % recipients) if 'Bcc' in extra_headers: debug(logger, " Bcc: %s" % extra_headers['Bcc']) debug(logger, " Body:") for line in mail_text.splitlines(): if isinstance(line, str): line = line.decode('utf-8', 'replace') debug(logger, line) if not dry_run: # Since we need to send the original changesfile as an # attachment the sendmail() method will be used as opposed to # simple_sendmail(). message = MIMEMultipart() message['from'] = from_addr message['subject'] = subject message['to'] = recipients # Set the extra headers if any are present. for key, value in extra_headers.iteritems(): message.add_header(key, value) # Add the email body. message.attach( MIMEText(sanitize_string(mail_text).encode('utf-8'), 'plain', 'utf-8')) if attach_changes: # Add the original changesfile as an attachment. if changesfile_content is not None: changesfile_text = sanitize_string(changesfile_content) else: changesfile_text = ("Sorry, changesfile not available.") attachment = MIMEText( changesfile_text.encode('utf-8'), 'plain', 'utf-8') attachment.add_header( 'Content-Disposition', 'attachment; filename="changesfile"') message.attach(attachment) # And finally send the message. sendmail(message)