def main(): messages = [] for url in RSS_URLS: messages += download_nzbs(url) #if len(messages) > 0: # from xmlrpclib import ServerProxy # server = ServerProxy('http://caliburn.csh.rit.edu:9611/') # for msg in messages: # server.message('hella: %s' %msg) if MAIL_ENABLED and len(messages) > 0: from email.Message import Message #print 'Sending email to %s' % EMAIL_TO email = Message() email.set_unixfrom(MAIL_FROM) email.add_header('Subject', '[hella] Queued %s files' % len(messages)) content = '' for msg in messages: content += '%s\r\n' % msg email.set_payload(content) email = email.as_string() server = SMTP(MAIL_SERVER) server.sendmail(MAIL_FROM, MAIL_TO, email) server.quit()
def handler(doc): # If all the addresses aren't email addresses, we pass... check = [doc['from']] + doc['to'] + doc.get('cc', []) + doc.get('bcc', []) for c in check: if c[0] != 'email': logger.info('skipping %(_id)r - not all email addresses', doc) return # all addresses are emails - so off we go... smtp_items = {} m = Message() (_, addr) = doc['from'] smtp_items['smtp_from'] = addr m.add_header('From', formataddr((doc['from_display'], doc['from'][1]))) smtp_to = smtp_items['smtp_to'] = [] for (_, addr), name in zip(doc.get('to', []), doc.get('to_display', [])): m.add_header('To', formataddr((name, addr))) smtp_to.append(addr) for (_, addr), name in zip(doc.get('cc', []), doc.get('cc_display', [])): m.add_header('CC', formataddr((name, addr))) smtp_to.append(addr) for (_, addr), name in zip(doc.get('bcc', []), doc.get('bcc_display', [])): m.add_header('BCC', formataddr((name, addr))) smtp_to.append(addr) m.add_header("Subject", doc['subject']) # for now body is plain-text as-is. m.set_payload(doc['body'], 'utf-8') attach_info = {'smtp_body': {'data': m.as_string()}} emit_schema('rd.msg.outgoing.smtp', smtp_items, attachments=attach_info)
def create_msg(v, rcptlist=None, origmsg=None, template=None): """Create a DSN message from a template. Template must be '\n' separated. v - an object whose attributes are used for substitutions. Must have sender and receiver attributes at a minimum. rcptlist - used to set v.rcpt if given origmsg - used to set v.subject and v.spf_result if given template - a '\n' separated string with python '%(name)s' substitutions. """ if not template: return None if hasattr(v, 'perm_error'): # likely to be an spf.query, try translating for backward compatibility q = v v = Vars() try: v.heloname = q.h v.sender = q.s v.connectip = q.i v.receiver = q.r v.sender_domain = q.o v.result = q.result v.perm_error = q.perm_error except: v = q if rcptlist: v.rcpt = '\n\t'.join(rcptlist) if origmsg: try: v.subject = origmsg['Subject'] except: v.subject = '(none)' try: v.spf_result = origmsg['Received-SPF'] except: v.spf_result = None msg = Message() msg.add_header('X-Mailer', 'PyMilter-' + Milter.__version__) msg.set_type('text/plain') hdrs, body = template.split('\n\n', 1) for ln in hdrs.splitlines(): name, val = ln.split(':', 1) msg.add_header(name, (val % v.__dict__).strip()) msg.set_payload(body % v.__dict__) # add headers if missing from old template if 'to' not in msg: msg.add_header('To', v.sender) if 'from' not in msg: msg.add_header('From', 'postmaster@%s' % v.receiver) if 'auto-submitted' not in msg: msg.add_header('Auto-Submitted', 'auto-generated') return msg
def create_msg(v,rcptlist=None,origmsg=None,template=None): """Create a DSN message from a template. Template must be '\n' separated. v - an object whose attributes are used for substitutions. Must have sender and receiver attributes at a minimum. rcptlist - used to set v.rcpt if given origmsg - used to set v.subject and v.spf_result if given template - a '\n' separated string with python '%(name)s' substitutions. """ if not template: return None if hasattr(v,'perm_error'): # likely to be an spf.query, try translating for backward compatibility q = v v = Vars() try: v.heloname = q.h v.sender = q.s v.connectip = q.i v.receiver = q.r v.sender_domain = q.o v.result = q.result v.perm_error = q.perm_error except: v = q if rcptlist: v.rcpt = '\n\t'.join(rcptlist) if origmsg: try: v.subject = origmsg['Subject'] except: v.subject = '(none)' try: v.spf_result = origmsg['Received-SPF'] except: v.spf_result = None msg = Message() msg.add_header('X-Mailer','PyMilter-'+Milter.__version__) msg.set_type('text/plain') hdrs,body = template.split('\n\n',1) for ln in hdrs.splitlines(): name,val = ln.split(':',1) msg.add_header(name,(val % v.__dict__).strip()) msg.set_payload(body % v.__dict__) # add headers if missing from old template if 'to' not in msg: msg.add_header('To',v.sender) if 'from' not in msg: msg.add_header('From','postmaster@%s'%v.receiver) if 'auto-submitted' not in msg: msg.add_header('Auto-Submitted','auto-generated') return msg
def _convert_to_mbox_msg(self, msg): file_ids = list(msg.objectIds('File')) encoding = "utf-8" # true only if we have attachments if file_ids: enc_msg = MIMEMultipart() txt = MIMEText(msg.body.encode(encoding)) enc_msg.attach(txt) else: enc_msg = Message() enc_msg.set_payload(msg.body.encode(encoding)) enc_msg['From'] = encode_header(msg.from_addr, encoding) enc_msg['To'] = encode_header(self.context.mailto, encoding) enc_msg['Subject'] = encode_header(msg.subject, encoding).replace("\n", " ").strip() enc_msg['Date'] = encode_header(str(msg.date), encoding) enc_msg['Message-id'] = encode_header(msg.message_id, encoding) if msg.references: enc_msg['References'] = encode_header(" ".join(msg.references), encoding) if msg.in_reply_to: enc_msg['In-reply-to'] = encode_header(msg.in_reply_to, encoding) ctime = str(msg.date) enc_msg.set_unixfrom("From %s %s" % (parseaddr(msg.from_addr)[1], ctime)) for file_id in file_ids: file = msg._getOb(file_id) data = file.data if not isinstance(data, basestring): data = str(data) content_type = file.getContentType() if content_type == 'message/rfc822': attachment = message_from_string(data) else: attachment = Message() attachment.add_header('Content-Disposition', 'attachment', filename=file.title) attachment.add_header('Content-Type', content_type) attachment.set_payload(data) enc_msg.attach(attachment) try: retval = enc_msg.as_string(unixfrom=True) except TypeError, e: raise
def addAttachment(self, content, content_type='application/octet-stream', inline=False, filename=None, charset=None): attachment = Message() if charset and isinstance(content, unicode): content = content.encode(charset) attachment.add_header('Content-Type', content_type) if inline: disposition = 'inline' else: disposition = 'attachment' disposition_kwargs = {} if filename is not None: disposition_kwargs['filename'] = filename attachment.add_header( 'Content-Disposition', disposition, **disposition_kwargs) attachment.set_payload(content, charset) self.encodeOptimally(attachment) self.attachments.append(attachment)
def test_sendmail_with_email_header(self): """Check the timeline is ok even if there is an email.Header. See https://bugs.launchpad.net/launchpad/+bug/885972 """ fake_mailer = RecordingMailer() self.useFixture(ZopeUtilityFixture(fake_mailer, IMailDelivery, 'Mail')) subject_str = self.getUniqueString('subject') subject_header = email.header.Header(subject_str) message = Message() message.add_header('From', '*****@*****.**') message['Subject'] = subject_header message.add_header('To', '*****@*****.**') with CaptureTimeline() as ctl: sendmail.sendmail(message) self.assertEquals(fake_mailer.from_addr, '*****@*****.**') self.assertEquals(fake_mailer.to_addr, ['*****@*****.**']) self.checkTimelineHasOneMailAction(ctl.timeline, subject=subject_str)
def test_sendmail_with_email_header(self): """Check the timeline is ok even if there is an email.Header. See https://bugs.launchpad.net/launchpad/+bug/885972 """ fake_mailer = RecordingMailer() self.useFixture(ZopeUtilityFixture( fake_mailer, IMailDelivery, 'Mail')) subject_str = self.getUniqueString('subject') subject_header = email.header.Header(subject_str) message = Message() message.add_header('From', '*****@*****.**') message['Subject'] = subject_header message.add_header('To', '*****@*****.**') with CaptureTimeline() as ctl: sendmail.sendmail(message) self.assertEquals(fake_mailer.from_addr, '*****@*****.**') self.assertEquals(fake_mailer.to_addr, ['*****@*****.**']) self.checkTimelineHasOneMailAction(ctl.timeline, subject=subject_str)
def notifyModerators(self, moderators, article): """ Send an article to a list of group moderators to be moderated. @param moderators: A C{list} of C{str} giving RFC 2821 addresses of group moderators to notify. @param article: The article requiring moderation. @type article: L{Article} @return: A L{Deferred} which fires with the result of sending the email. """ # Moderated postings go through as long as they have an Approved # header, regardless of what the value is group = article.getHeader('Newsgroups') subject = article.getHeader('Subject') if self._sender is None: # This case should really go away. This isn't a good default. sender = 'twisted-news@' + socket.gethostname() else: sender = self._sender msg = Message() msg['Message-ID'] = smtp.messageid() msg['From'] = sender msg['To'] = ', '.join(moderators) msg['Subject'] = 'Moderate new %s message: %s' % (group, subject) msg['Content-Type'] = 'message/rfc822' payload = Message() for header, value in article.headers.values(): payload.add_header(header, value) payload.set_payload(article.body) msg.attach(payload) out = StringIO.StringIO() gen = Generator(out, False) gen.flatten(msg) msg = out.getvalue() return self.sendmail(self._mailhost, sender, moderators, msg)
def test_epilogue(self): fp = openfile('msg_21.txt') try: text = fp.read() finally: fp.close() msg = Message() msg['From'] = '*****@*****.**' msg['To'] = '*****@*****.**' msg['Subject'] = 'Test' msg.preamble = 'MIME message\n' msg.epilogue = 'End of MIME message\n' msg1 = MIMEText('One') msg2 = MIMEText('Two') msg.add_header('Content-Type', 'multipart/mixed', boundary='BOUNDARY') msg.add_payload(msg1) msg.add_payload(msg2) sfp = StringIO() g = Generator(sfp) g(msg) self.assertEqual(sfp.getvalue(), text)
def addAttachment(self, content, content_type='application/octet-stream', inline=False, filename=None, charset=None): attachment = Message() if charset and isinstance(content, unicode): content = content.encode(charset) attachment.add_header('Content-Type', content_type) if inline: disposition = 'inline' else: disposition = 'attachment' disposition_kwargs = {} if filename is not None: disposition_kwargs['filename'] = filename attachment.add_header('Content-Disposition', disposition, **disposition_kwargs) attachment.set_payload(content, charset) self.encodeOptimally(attachment) self.attachments.append(attachment)
def send_email(fromAddress, toAddress, subject, message, smtp_server=SMTP_SERVER): '''Send an email if there's an error. This will be replaced by sending messages to a log later. ''' msg = Message() msg.add_header('To', toAddress) msg.add_header('From', fromAddress) msg.add_header('Subject', subject) msg.set_payload(message) smtp = smtplib.SMTP(smtp_server) smtp.sendmail(fromAddress, [toAddress], msg.as_string()) smtp.quit()
def send_email(fromAddress, toAddress, subject, message, smtp_server=SMTP_SERVER): """Send an email if there's an error. This will be replaced by sending messages to a log later. """ msg = Message() msg.add_header("To", toAddress) msg.add_header("From", fromAddress) msg.add_header("Subject", subject) msg.set_payload(message) smtp = smtplib.SMTP(smtp_server) smtp.sendmail(fromAddress, [toAddress], msg.as_string()) smtp.quit()
def send_email(fromAddress, toAddress, subject, message): '''Send an email if there's an error. This will be replaced by sending messages to a log later. ''' msg = Message() msg.add_header('To', toAddress) msg.add_header('From', fromAddress) msg.add_header('Subject', subject) msg.set_payload(message) smtp = smtplib.SMTP('bastion') smtp.sendmail(fromAddress, [toAddress], msg.as_string()) smtp.quit()
def __call__(self, sender, recipient, subject, body): msg = Message() msg.add_header("Subject", subject) msg.add_header("To", str(recipient)) msg.add_header("From", str(sender)) msg.set_payload(body) command = [ self.SENDMAIL_PATH, '-i', '-f', sender.address, recipient.address ] command = Command(command) command.tochild.write(msg.as_string()) command.tochild.close() command.wait() if command.exitcode != 0: raise Error("sendmail failed (%d): %s" % (command.exitcode, command.output))
class Out(object): def get(): global theOutput if theOutput is None: raise Error, "No output object has been installed." return theOutput get = staticmethod(get) def __init__(self): global theOutput if theOutput is not None: raise Error, "An output object has already been installed." # Hook standard output self.real_stdout = sys.stdout self.buffer = cStringIO.StringIO() sys.stdout = self.buffer # Default content type self.contenttype = "text/html" # No headers self.headers = Message() self.sendEntityHeaders = True self.redirecting = False self.cookies = Cookie.SimpleCookie() # Detect compression self.acceptsGzip = 0 if os.environ.get("HTTP_ACCEPT_ENCODING", "").find("gzip") != -1: self.acceptsGzip = 1 # Trap exiting a script to force output to close self.ran = False theOutput = self sys.exitfunc = Close def getResponseBody(self, body): if self.acceptsGzip: # gzip writes the time into its header # this kills cacheability, so we hack the time to be 0 real_time = time.time time.time = lambda a=None: 0 zbuf = cStringIO.StringIO() zfile = gzip.GzipFile(mode="wb", fileobj=zbuf) zfile.write(body) zfile.close() self.headers["Content-Encoding"] = "gzip" output = zbuf.getvalue() time.time = real_time return output else: return body def close(self): if self.ran: return # Restore stdout so we can pipe our data out sys.stdout = self.real_stdout body = self.buffer.getvalue() headers = "" self.buffer.close() # Look for any headers already written if re.search("location:", body, re.I): self.redirecting = True self.sendEntityHeaders = False msg = HeaderParser().parsestr(body, True) # Add written headers to our header list for name, value in msg.items(): self.headers.add_header(name, value) elif re.search("content-type:", body, re.I): try: endOfHeaders = body.index("\n\n") headers = body[:endOfHeaders] body = body[endOfHeaders + 2 :] msg = HeaderParser().parsestr(headers, True) # Add written headers to our header list for name, value in msg.items(): self.headers.add_header(name, value) except ValueError: raise error, "Headers detected, sort of" # Get the response body, possibly compressed if self.sendEntityHeaders: body = self.getResponseBody(body) del self.headers["Content-Length"] self.headers["Content-Length"] = str(len(body)) if not self.redirecting and (not "content-type" in self.headers): self.headers["Content-Type"] = self.contenttype etag = base64.encodestring(md5.new(body).digest())[:-1] self.headers["ETag"] = '"' + etag + '"' if "HTTP_IF_NONE_MATCH" in os.environ: if etag in ETags(os.environ["HTTP_IF_NONE_MATCH"]): print "Status: 304 Not Modified" self.sendEntityHeaders = False self._send_headers() if self.sendEntityHeaders: sys.stdout.write(body) self.ran = True def _send_headers(self): for header in self.headers.keys(): if (not self.sendEntityHeaders) and (header.lower() in entity_headers): continue print header + ": " + str(self.headers[header]) if len(self.cookies) > 0: print self.cookies.output() print
def construct_message(imap, msg_format, msg_to, msg_from, msg_date, msg_subject, msg_body): msg = Message() msg.add_header('Date', formatdate(time.mktime(msg_date.timetuple()))) msg.add_header('Message-Id', create_id(msg_date, msg_from)) msg.add_header('To', msg_to) msg.add_header('From', msg_from) msg.add_header('MIME-Version', '1.0') msg.add_header('Subject', msg_subject) payload = Message() payload.add_header('Content-Type', msg_format) if msg_format in ('text/html', 'text/plain'): payload.add_header('Content-Transfer-Encoding', '8bit') payload.set_payload(''.join(msg_body)) else: payload.add_header('Content-Transfer-Encoding', 'base64') payload.add_header('Content-Disposition', 'attachment; filename="%s"' % msg_subject) payload.set_payload(encodestring(''.join(msg_body)).decode()) for item in payload.items(): msg.add_header(item[0], item[1]) msg.set_payload(payload.get_payload()) try: msg.as_string() except Exception, e: print e
# Copyright (C) 2001 Python Software Foundation
def repost(self,cancelid): self.__cancelid = cancelid self._getCancelMsg() self._getOriginalMsg() text1 = self.__origMsg.get_payload() text2 = self.__cancelMsg.as_string() newmsg = Message() newmsg['Sender'] = self.__reposter newmsg['Newsgroups'] = self.__origMsg['Newsgroups'] newmsg['From'] = self.__origMsg['From'] newmsg['Subject'] = '[REPOST] ' + self.__origMsg['Subject'] if self.__origMsg.has_key('References'): newmsg['References'] = self.__origMsg['References'] newmsg['Supersedes'] = self.__origMsg['Message-ID'] if self.__origMsg.has_key('Followup-To'): newmsg['Followup-To'] = self.__origMsg['Followup-To'] if self.__origMsg.has_key('Reply-To'): newmsg['Reply-To'] = self.__origMsg['Reply-To'] if self.__origMsg.has_key('Organization'): newmsg['Organization'] = self.__origMsg['Organization'] newmsg['X-Original-Path'] = self.__origMsg['Path'] from datetime import datetime now = datetime.now() s1 = now.strftime("%y%j%H%M%S.") s2 = self.__origMsg['Message-ID'] s2 = s2[1:-1] newmsg['Message-ID'] = '<REPOST.' + s1 + s2 + ">" newmsg['X-Original-Message-ID'] = self.__origMsg['Message-ID'] if self.__origMsg.has_key('NNTP-Posting-Host'): newmsg['X-Original-NNTP-Posting-Host'] = self.__origMsg['NNTP-Posting-Host'] if self.__origMsg.has_key('NNTP-Posting-Date'): newmsg['X-Original-NNTP-Posting-Date'] = self.__origMsg['NNTP-Posting-Date'] newmsg['X-Original-Date'] = self.__origMsg['Date'] newmsg['X-Comment'] = 'Reposted by NNTPRepost ' + self.__reposter newmsg.add_header('X-Comment', 'The following Usenet article was cancelled') newmsg.add_header('X-Comment', 'more than likely by someone other than the original poster.') newmsg.add_header('X-Comment', 'Please see the end of this posting for a copy of the cancel.') newmsg.add_header('X-Comment', self.__reposter) newmsg['X-Reposted-By'] = newmsg['Sender'] newmsg['Path'] = '!NNTPRepost' newmsg['X-No-Archive'] = 'yes' if self.__origMsg.has_key('MIME-Version'): newmsg['MIME-Version'] = self.__origMsg['MIME-Version'] if self.__origMsg.has_key('Content-Type'): newmsg['Content-Type'] = self.__origMsg['Content-Type'] if self.__origMsg.has_key('Content-Transfer-Encoding'): newmsg['Content-Transfer-Encoding'] = self.__origMsg['Content-Transfer-Encoding'] text = text1 + "\n========= WAS CANCELLED BY =======:\n" + text2 text = text1 + "\n-- \n========= WAS CANCELLED BY =======:\n" + text2 newmsg.set_payload(text) self.__nntpc.post(newmsg)
def forum_post_as_email(self, forum, post): '''Convert a post to email''' topic = post.topic sre, subject = re.match(r'(Re: )?(.*)', post.subject).groups() if subject == '': if post.pid != topic.firstpost: sre = 'Re: ' subject = topic.title or 'topic %s' % topic.tid subject = (sre or '') + forum.subjectPrefix + subject if post.datetime is not None: pass zauthor,n = re.subn(r'[^-A-Za-z0-9]+','_', post.author) fromm = _subst(self.fromPattern, u=zauthor) msgid = _subst(self.messageIdPattern, p=post.pid) hbody = '<html><body>%s</body></html>' % post.body.encode('utf-8') try: from email.Message import Message from email.Header import Header from email.Utils import formatdate # Force quoted-printable for utf-8 instead of base64 (for Thunderbird "View source") import email.Charset as cs cs.add_charset('utf-8', cs.SHORTEST, cs.QP, 'utf-8') except ImportError: from email.message import Message from email.header import Header from email.utils import formatdate msg = Message() msg.add_header('From', fromm) msg.add_header('To', forum.recipient) hsubj = Header(subject) msg.add_header('Subject', str(hsubj)) msg.add_header('Message-ID', '<%s>' % msgid) if topic.firstpost: firstid = _subst(self.messageIdPattern, p=topic.firstpost) msg.add_header('In-Reply-To', '<%s>' % firstid) msg.add_header('References', '<%s>' % firstid) if post.datetime is not None: date = formatdate(post.datetime) msg.add_header('Date', date) msg.set_payload(hbody) msg.set_type('text/html') msg.set_charset('utf-8') return msg.as_string()
which bugzilla is telling us is not an account in bugzilla. If you could please set up an account in bugzilla with this address or change your email address on your Fedora Account to match an existing bugzilla account this would let us go forward. Note: this message is being generated by an automated script. You'll continue getting this message until the problem is resolved. Sorry for the inconvenience. Thank you, The Fedora Account System %(admin_email)s ''' % {'name': person.person.human_name, 'email': person.email, 'admin_email': ADMINEMAIL} msg.add_header('To', person.email) msg.add_header('From', ADMINEMAIL) msg.add_header('Subject', 'Fedora Account System and Bugzilla Mismatch') msg.set_payload(message) smtp = smtplib.SMTP(MAILSERVER) smtp.sendmail(ADMINEMAIL, [person.email], msg.as_string()) smtp.quit() recipients = [e for e in NOTIFYEMAIL if e != '$USER'] if recipients and no_bz_account: smtplib.SMTP(MAILSERVER) msg = Message() people = [] for person in no_bz_account: if person.person.status == 'Active': people.append(' %(user)s -- %(name)s -- %(email)s' % {'name': person.person.human_name, 'email': person.email,
def verpdeliver(mlist, msg, msgdata, envsender, failures, conn): for recip in msgdata['recips']: # We now need to stitch together the message with its header and # footer. If we're VERPIng, we have to calculate the envelope sender # for each recipient. Note that the list of recipients must be of # length 1. # # BAW: ezmlm includes the message number in the envelope, used when # sending a notification to the user telling her how many messages # they missed due to bouncing. Neat idea. msgdata['recips'] = [recip] # Make a copy of the message and decorate + delivery that msgcopy = copy.deepcopy(msg) Decorate.process(mlist, msgcopy, msgdata) # Calculate the envelope sender, which we may be VERPing if msgdata.get('verp'): bmailbox, bdomain = Utils.ParseEmail(envsender) rmailbox, rdomain = Utils.ParseEmail(recip) if rdomain is None: # The recipient address is not fully-qualified. We can't # deliver it to this person, nor can we craft a valid verp # header. I don't think there's much we can do except ignore # this recipient. syslog('smtp', 'Skipping VERP delivery to unqual recip: %s', recip) continue d = {'bounces': bmailbox, 'mailbox': rmailbox, 'host' : DOT.join(rdomain), } envsender = '%s@%s' % ((mm_cfg.VERP_FORMAT % d), DOT.join(bdomain)) if mlist.personalize == 2: # When fully personalizing, we want the To address to point to the # recipient, not to the mailing list del msgcopy['to'] name = None if mlist.isMember(recip): name = mlist.getMemberName(recip) if name: # Convert the name to an email-safe representation. If the # name is a byte string, convert it first to Unicode, given # the character set of the member's language, replacing bad # characters for which we can do nothing about. Once we have # the name as Unicode, we can create a Header instance for it # so that it's properly encoded for email transport. charset = Utils.GetCharSet(mlist.getMemberLanguage(recip)) if charset == 'us-ascii': # Since Header already tries both us-ascii and utf-8, # let's add something a bit more useful. charset = 'iso-8859-1' charset = Charset(charset) codec = charset.input_codec or 'ascii' if not isinstance(name, UnicodeType): name = unicode(name, codec, 'replace') name = Header(name, charset).encode() msgcopy['To'] = formataddr((name, recip)) else: msgcopy['To'] = recip # We can flag the mail as a duplicate for each member, if they've # already received this message, as calculated by Message-ID. See # AvoidDuplicates.py for details. del msgcopy['x-mailman-copy'] if msgdata.get('add-dup-header', {}).has_key(recip): msgcopy['X-Mailman-Copy'] = 'yes' # GPG encryption if 'encrypted_gpg' in msgdata and msgdata['encrypted_gpg'] and mlist.encrypt_policy!=0: # Encryption is not forbidden in config try: keyids=mlist.getGPGKeyIDs(recip) except: keyids=None if enforceEncryptPolicy(mlist,msg,msgdata) and keyids==None: syslog('gpg','Encryption mandatory, but no keys found for %s: '\ 'Discarding message',recip) failures[recip]=(550,'Encryption mandatory, but no keys found') return gh = GPGUtils.GPGHelper(mlist) # Extract / generate plaintext gpg_use_inlineformat = False # TODO: Create config setting if not msgcopy.is_multipart() and gpg_use_inlineformat: plaintext=msgcopy.get_payload() else: if not msgcopy.is_multipart(): plaintext = 'Content-Type: %s\n' \ 'Content-Disposition: inline\n' \ % msgcopy.get('Content-Type') if not msgcopy.get('Content-Transfer-Encoding') is None: plaintext += 'Content-Transfer-Encoding: %s\n' \ % msgcopy.get('Content-Transfer-Encoding') plaintext += '\n%s' % msgcopy.get_payload() else: hp = HeaderParser() tmp = msgcopy.as_string() tmpmsg = hp.parsestr(tmp) plaintext = 'Content-Type: %s\n' \ 'Content-Disposition: inline\n\n%s' \ % (msgcopy.get('Content-Type'),tmpmsg.get_payload()) # Do encryption, report errors ciphertext = None if not keyids is None: # Can encrypt. # No signing policy, or voluntary and original wasn't signed: just encrypt if mlist.sign_policy == 0 or \ (mlist.sign_policy==1 and not msgdata['signed_gpg']): ciphertext = gh.encryptMessage(plaintext,keyids) else: ciphertext = gh.encryptSignMessage(plaintext,keyids) if ciphertext==None: # Must always encrypt, since if we arrived here encrypt_policy # is either Mantatory or (Voluntary and incoming msg was encrypted). syslog('gpg',"Can't encrypt message to %s: " \ "Discarding message",keyids) failures[recip]=(550,'Unable to encrypt message') return # Compile encrypted message if not ciphertext is None: if msgcopy.has_key('Content-Transfer-Encoding'): msgcopy.replace_header('Content-Transfer-Encoding','7bit') else: msgcopy.add_header('Content-Transfer-Encoding','7bit') if not msgcopy.is_multipart() and gpg_use_inlineformat: msgcopy.set_payload(ciphertext) msgcopy.set_param('x-action','pgp-encrypted') else: msgcopy.replace_header('Content-Type','multipart/encrypted') msgcopy.set_param('protocol','application/pgp-encrypted') msgcopy.set_payload(None) submsg = Message() submsg.add_header('Content-Type','application/pgp-encrypted') submsg.set_payload('Version: 1\n') msgcopy.attach(submsg) submsg = Message() submsg.add_header('Content-Type','application/octet-stream; name="encrypted.asc"') submsg.add_header('Content-Disposition','inline; filename="encrypted.asc"') submsg.set_payload(ciphertext) msgcopy.attach(submsg) syslog('gpg','Sending encrypted message to %s',recip) else: syslog('gpg','Sending unencrypted message to %s',recip) if 'encrypted_smime' in msgdata and msgdata['encrypted_smime'] and mlist.encrypt_policy != 0: # FIXME: this is as crude as can be sm = SMIMEUtils.SMIMEHelper(mlist) recipfile = sm.getSMIMEMemberCertFile(recip) if not recipfile: failures[recip]=(550,'No S/MIME key found') return else: plaintext=msgcopy.get_payload() if not msgcopy.is_multipart(): plaintext = msgcopy.get_payload() syslog('gpg', "About to S/MIME encrypt plaintext from singlepart") else: # message contains e.g. signature? # FIXME we fetch only the first attachment. We search for # attachments only 2 levels deep. That's suboptimal... # perhaps the PGP way (invoking # hp = HeaderParser() # ) is better. submsgs = msgcopy.get_payload() submsg = submsgs[0] if not submsg.is_multipart(): plaintext = submsg.get_payload() else: subsubmsgs = submsg.get_payload() subsubmsg = subsubmsgs[0] plaintext = subsubmsg.get_payload() syslog('gpg', "About to S/MIME encrypt plaintext from multipart") if mlist.sign_policy == 0 or \ (mlist.sign_policy==1 and not msgdata['signed_smime']): ciphertext = sm.encryptMessage(plaintext,recipfile) else: ciphertext = sm.encryptSignMessage(plaintext,recipfile) # deal with both header and body-part of ciphertext (header, body) = ciphertext.split("\n\n", 1) for l in header.split("\n"): (k, v) = l.split(": ", 1) # behave sane with borken openssl like 0.9.7e (e.g. Debian's 0.9.7e-3sarge1) # openssl 0.9.8a-4a0.sarge.1 is known to work OK. # A borken openssl (and therefore sm.encryptMessage) returns # Content-Type: application/x-pkcs7-mime; name="smime.p7m" # while we need a # Content-Type: application/x-pkcs7-mime; smime-type=enveloped-data; name="smime.p7m" if v == 'application/x-pkcs7-mime; name="smime.p7m"': v = 'application/x-pkcs7-mime; smime-type=enveloped-data; name="smime.p7m"' try: msgcopy.replace_header(k, v) except KeyError: msgcopy.add_header(k, v) msgcopy.set_payload(body) # For the final delivery stage, we can just bulk deliver to a party of # one. ;) bulkdeliver(mlist, msgcopy, msgdata, envsender, failures, conn)