def kindToMessageObject(mailStamp): """ This method converts an item stamped as MailStamp to an email message string a Chandler C{MailMessage} object @param mailMessage: A Chandler C{MailMessage} @type mailMessage: C{MailMessage} @return: C{Message.Message} """ view = mailStamp.itsItem.itsView mailStampOccurrence, mailStampMaster = getRecurrenceMailStamps(mailStamp) isEvent = has_stamp(mailStampOccurrence, EventStamp) isTask = has_stamp(mailStampOccurrence, TaskStamp) messageObject = Message.Message() # Create a messageId if none exists mId = getattr(mailStampMaster, "messageId", None) if not mId: mId = createMessageID() populateHeader(messageObject, 'Message-ID', mId) populateEmailAddresses(mailStampMaster, messageObject) populateStaticHeaders(messageObject) if hasattr(mailStampMaster, "dateSentString"): date = mailStampMaster.dateSentString else: date = datetimeToRFC2822Date(datetime.now(view.tzinfo.default)) messageObject["Date"] = date inReplyTo = getattr(mailStampMaster, "inReplyTo", None) subject = mailStampOccurrence.subject if subject is not None: # Fixes bug 10254 where the title of a Item # that contained a new line was breaking the # the rfc2822 formatting of the outgoing message. subject = subject.replace("\n", "") if inReplyTo: messageObject["In-Reply-To"] = inReplyTo if mailStampMaster.referencesMID: messageObject["References"] = " ".join(mailStampMaster.referencesMID) populateHeader(messageObject, 'Subject', subject, encode=True) try: payload = getMessageBody(mailStampOccurrence) except AttributeError: payload = u"" if not payload: # bug 12262, Outlook doesn't like multipart/alternative if there's # no payload, so add a few carriage returns to empty bodies payload += "\r\n\r\n" if isTask or isEvent and payload and \ not payload.endswith(u"\r\n\r\n"): # Chandler outgoing Tasks and Events contain # an ics attachment. # Many mail readers add attachment icons # at the end of the message body. # This can be distracting and visually # ugly. Appending two line breaks to the # payload provides better alignment in # mail readers such as Apple Mail and # Thunderbird. payload += u"\r\n\r\n" messageObject.set_type("multipart/mixed") # Create a multipart/alernative MIME Part # that will contain the Chandler eimml and # the body of the message as alternative # parts. Doing this prevents users from seeing # the Chandler eimml which is machine readable # xml code and is not displayable to the user. alternative = MIMEMultipart("alternative") # Serialize and attach the eimml can raise ConflictsPending eimml = outbound(getPeers(mailStampMaster), mailStampMaster.itsItem, OUTBOUND_FILTERS) eimmlPayload = MIMEBase64Encode(eimml, 'text', 'eimml') # Since alternative parts are in order from least # renderable to most renderable add the eimml payload # first. alternative.attach(eimmlPayload) # Attach the body text mt = MIMEBase64Encode(payload.encode('utf-8')) # Add the email body text to the alternative part alternative.attach(mt) # Add the alternative part to the mail multipart/mixed # main content type. messageObject.attach(alternative) #XXX There is no attachement support in 1.0 #hasAttachments = mailStamp.getNumberOfAttachments() > 0 if isEvent or isTask: # Format this message as an ICalendar object from osaf.sharing import (serialize, VObjectSerializer, SharingTranslator, remindersFilter) items = [mailStampMaster.itsItem] for mod in EventStamp(mailStampMaster).modifications or []: if not checkTriageOnly(mod): items.append(mod) calendar = serialize(mailStamp.itsItem.itsView, items, SharingTranslator, VObjectSerializer, filter=remindersFilter) # don't use method REQUEST because it will cause Apple iCal to treat # the ics attachment as iMIP calendar.add('method').value="PUBLISH" ics = calendar.serialize() # returns a UTF-8 encoded str # Attach the ICalendar object icsPayload = MIMEBase64Encode(ics, 'text', 'calendar', method='PUBLISH') # L10N: The filename of Events and Tasks emailed from Chandler fname = Header.Header(_(u"ChandlerItem.ics")).encode() icsPayload.add_header("Content-Disposition", "attachment", filename=fname) messageObject.attach(icsPayload) #XXX: There is no attachment support in 1.0 via # the MailStamp.mimeContent. Commenting out this code # for now. # #if hasAttachments: # attachments = mailStamp.getAttachments() # # for attachment in attachments: # if has_stamp(attachment, MailStamp): # # The attachment is another MailMessage # try: # rfc2822 = binaryToData(MailStamp(attachment).rfc2822Message) # except AttributeError: # rfc2822 = kindToMessageText(attachment, False) # # message = email.message_from_string(rfc2822) # rfc2822Payload = MIMEMessage(message) # messageObject.attach(rfc2822Payload) # # else: # if isinstance(attachment, MIMEText) and \ # attachment.mimeType == u"text/calendar": # icsPayload = MIMENonMultipart('text', 'calendar', \ # method='REQUEST', _charset="utf-8") # # fname = Header.Header(attachment.filename).encode() # icsPayload.add_header("Content-Disposition", "attachment", filename=fname) # icsPayload.set_payload(attachment.data.encode('utf-8')) # messageObject.attach(icsPayload) return messageObject
def _prepareForSend(self, mailMessageUUID): """Sends a mail message via SMTP using the account and mailMessage passed to this classes __init__ method using the Twisted Asych Reactor""" if __debug__: trace("_prepareForSend") if self.cancel: return self._resetClient() # Refresh our view before retrieving Account info self.view.refresh() self._getAccount() # If currently sending a message put the next request in the Queue. try: # Just in case a cancel was requested after the above cancel check # return here instead of seeing if the message should go in the queue if self.cancel: return self._resetClient() msg = self._getMailMessage(mailMessageUUID) mailStampOccurrence, masterMailStamp = getRecurrenceMailStamps(msg) # The isOnline check is performed in the Twisted thread # so pass in a view. if self.mailMessage is not None or not Globals.mailService.isOnline( self.view): newMessage = masterMailStamp try: sending = (self.mailMessage.itsItem is newMessage.itsItem) except: sending = False inQueue = False # Check that the mailMessage in not already Queued for item in self.account.messageQueue: if item is newMessage.itsItem: if __debug__: trace( "SMTPClient Queue already contains message: %s" % mailMessageUUID) inQueue = True #Sending should always be False in offline mode if not inQueue and sending: # Check that the mailMessage in not currently being sent if __debug__: trace("SMTPClient currently sending message: %s" % mailMessageUUID) elif not inQueue: self.account.messageQueue.insert(0, newMessage.itsItem) # Update the item state newMessage.itsItem.changeEditState( Modification.queued, who=newMessage.getSender()) self.view.commit() if __debug__: trace("SMTPClient adding to the Queue message: %s" % mailMessageUUID) # The isOnline check is performed in the Twisted thread # so pass in a view. if not Globals.mailService.isOnline(self.view): setStatusMessage(constants.UPLOAD_OFFLINE % \ {'accountName': self.account.displayName, 'subject': mailStampOccurrence.subject}) return self.mailMessage = masterMailStamp setStatusMessage(constants.UPLOAD_START % \ {'accountName': self.account.displayName, 'subject': mailStampOccurrence.subject}) # handles all MailStamp level logic to support general sending # of mail as well as edit / update workflows masterMailStamp.outgoingMessage() sender = masterMailStamp.getSender() # use the individual occurrence, not the master, bug 9499 messageText = kindToMessageText(mailStampOccurrence) except Exception, e: if __debug__: trace(e) return self._mailFailure(e)
def kindToMessageObject(mailStamp): """ This method converts an item stamped as MailStamp to an email message string a Chandler C{MailMessage} object @param mailMessage: A Chandler C{MailMessage} @type mailMessage: C{MailMessage} @return: C{Message.Message} """ view = mailStamp.itsItem.itsView mailStampOccurrence, mailStampMaster = getRecurrenceMailStamps(mailStamp) isEvent = has_stamp(mailStampOccurrence, EventStamp) isTask = has_stamp(mailStampOccurrence, TaskStamp) messageObject = Message.Message() # Create a messageId if none exists mId = getattr(mailStampMaster, "messageId", None) if not mId: mId = createMessageID() populateHeader(messageObject, 'Message-ID', mId) populateEmailAddresses(mailStampMaster, messageObject) populateStaticHeaders(messageObject) if hasattr(mailStampMaster, "dateSentString"): date = mailStampMaster.dateSentString else: date = datetimeToRFC2822Date(datetime.now(view.tzinfo.default)) messageObject["Date"] = date inReplyTo = getattr(mailStampMaster, "inReplyTo", None) subject = mailStampOccurrence.subject if subject is not None: # Fixes bug 10254 where the title of a Item # that contained a new line was breaking the # the rfc2822 formatting of the outgoing message. subject = subject.replace("\n", "") if inReplyTo: messageObject["In-Reply-To"] = inReplyTo if mailStampMaster.referencesMID: messageObject["References"] = " ".join(mailStampMaster.referencesMID) populateHeader(messageObject, 'Subject', subject, encode=True) try: payload = getMessageBody(mailStampOccurrence) except AttributeError: payload = u"" if not payload: # bug 12262, Outlook doesn't like multipart/alternative if there's # no payload, so add a few carriage returns to empty bodies payload += "\r\n\r\n" if isTask or isEvent and payload and \ not payload.endswith(u"\r\n\r\n"): # Chandler outgoing Tasks and Events contain # an ics attachment. # Many mail readers add attachment icons # at the end of the message body. # This can be distracting and visually # ugly. Appending two line breaks to the # payload provides better alignment in # mail readers such as Apple Mail and # Thunderbird. payload += u"\r\n\r\n" messageObject.set_type("multipart/mixed") # Create a multipart/alernative MIME Part # that will contain the Chandler eimml and # the body of the message as alternative # parts. Doing this prevents users from seeing # the Chandler eimml which is machine readable # xml code and is not displayable to the user. alternative = MIMEMultipart("alternative") # Serialize and attach the eimml can raise ConflictsPending eimml = outbound(getPeers(mailStampMaster), mailStampMaster.itsItem, OUTBOUND_FILTERS) eimmlPayload = MIMEBase64Encode(eimml, 'text', 'eimml') # Since alternative parts are in order from least # renderable to most renderable add the eimml payload # first. alternative.attach(eimmlPayload) # Attach the body text mt = MIMEBase64Encode(payload.encode('utf-8')) # Add the email body text to the alternative part alternative.attach(mt) # Add the alternative part to the mail multipart/mixed # main content type. messageObject.attach(alternative) #XXX There is no attachement support in 1.0 #hasAttachments = mailStamp.getNumberOfAttachments() > 0 if isEvent or isTask: # Format this message as an ICalendar object from osaf.sharing import (serialize, VObjectSerializer, SharingTranslator, remindersFilter) items = [mailStampMaster.itsItem] for mod in EventStamp(mailStampMaster).modifications or []: if not checkTriageOnly(mod): items.append(mod) calendar = serialize(mailStamp.itsItem.itsView, items, SharingTranslator, VObjectSerializer, filter=remindersFilter) # don't use method REQUEST because it will cause Apple iCal to treat # the ics attachment as iMIP calendar.add('method').value = "PUBLISH" ics = calendar.serialize() # returns a UTF-8 encoded str # Attach the ICalendar object icsPayload = MIMEBase64Encode(ics, 'text', 'calendar', method='PUBLISH') # L10N: The filename of Events and Tasks emailed from Chandler fname = Header.Header(_(u"ChandlerItem.ics")).encode() icsPayload.add_header("Content-Disposition", "attachment", filename=fname) messageObject.attach(icsPayload) #XXX: There is no attachment support in 1.0 via # the MailStamp.mimeContent. Commenting out this code # for now. # #if hasAttachments: # attachments = mailStamp.getAttachments() # # for attachment in attachments: # if has_stamp(attachment, MailStamp): # # The attachment is another MailMessage # try: # rfc2822 = binaryToData(MailStamp(attachment).rfc2822Message) # except AttributeError: # rfc2822 = kindToMessageText(attachment, False) # # message = email.message_from_string(rfc2822) # rfc2822Payload = MIMEMessage(message) # messageObject.attach(rfc2822Payload) # # else: # if isinstance(attachment, MIMEText) and \ # attachment.mimeType == u"text/calendar": # icsPayload = MIMENonMultipart('text', 'calendar', \ # method='REQUEST', _charset="utf-8") # # fname = Header.Header(attachment.filename).encode() # icsPayload.add_header("Content-Disposition", "attachment", filename=fname) # icsPayload.set_payload(attachment.data.encode('utf-8')) # messageObject.attach(icsPayload) return messageObject
def _prepareForSend(self, mailMessageUUID): """Sends a mail message via SMTP using the account and mailMessage passed to this classes __init__ method using the Twisted Asych Reactor""" if __debug__: trace("_prepareForSend") if self.cancel: return self._resetClient() # Refresh our view before retrieving Account info self.view.refresh() self._getAccount() # If currently sending a message put the next request in the Queue. try: # Just in case a cancel was requested after the above cancel check # return here instead of seeing if the message should go in the queue if self.cancel: return self._resetClient() msg = self._getMailMessage(mailMessageUUID) mailStampOccurrence, masterMailStamp = getRecurrenceMailStamps(msg) # The isOnline check is performed in the Twisted thread # so pass in a view. if self.mailMessage is not None or not Globals.mailService.isOnline(self.view): newMessage = masterMailStamp try: sending = (self.mailMessage.itsItem is newMessage.itsItem) except: sending = False inQueue = False # Check that the mailMessage in not already Queued for item in self.account.messageQueue: if item is newMessage.itsItem: if __debug__: trace("SMTPClient Queue already contains message: %s" % mailMessageUUID) inQueue = True #Sending should always be False in offline mode if not inQueue and sending: # Check that the mailMessage in not currently being sent if __debug__: trace("SMTPClient currently sending message: %s" % mailMessageUUID) elif not inQueue: self.account.messageQueue.insert(0, newMessage.itsItem) # Update the item state newMessage.itsItem.changeEditState(Modification.queued, who=newMessage.getSender()) self.view.commit() if __debug__: trace("SMTPClient adding to the Queue message: %s" % mailMessageUUID) # The isOnline check is performed in the Twisted thread # so pass in a view. if not Globals.mailService.isOnline(self.view): setStatusMessage(constants.UPLOAD_OFFLINE % \ {'accountName': self.account.displayName, 'subject': mailStampOccurrence.subject}) return self.mailMessage = masterMailStamp setStatusMessage(constants.UPLOAD_START % \ {'accountName': self.account.displayName, 'subject': mailStampOccurrence.subject}) # handles all MailStamp level logic to support general sending # of mail as well as edit / update workflows masterMailStamp.outgoingMessage() sender = masterMailStamp.getSender() # use the individual occurrence, not the master, bug 9499 messageText = kindToMessageText(mailStampOccurrence) except Exception, e: if __debug__: trace(e) return self._mailFailure(e)