def test_makeHeader(self): e = mimeutil.EmailAddress( ' =?ISO-8859-1?Q?C=E9sar______?= fu bar <*****@*****.**>' ) header = e.makeHeader('To') e2 = mimeutil.EmailAddress(header.encode()) self.assertEquals(e, e2)
def test_slotData(self): """ Verify that L{DraftComposeFragment.slotData} returns a dictionary which reflects the message which was used as the draft. """ subject = u'subject text' body = u'hello, world?\n' to = u'*****@*****.**' cc = u'*****@*****.**' bcc = u'*****@*****.**' message = createMessage( self.composer, None, None, self.defaultFromAddress, [mimeutil.EmailAddress(to, mimeEncoded=False)], subject, body, [mimeutil.EmailAddress(cc, mimeEncoded=False)], [mimeutil.EmailAddress(bcc, mimeEncoded=False)], [], ) fragment = self.messageDetail._composeSomething(draft=message) slotData = fragment.slotData() self.assertEqual(slotData['to'], to) self.assertEqual(slotData['from'][0], self.defaultFromAddress) self.assertEqual(slotData['subject'], subject) self.assertEqual(slotData['message-body'], body) self.assertEqual(slotData['cc'], cc)
def test_ListHeader(self): emails = [] emails.append( mimeutil.EmailAddress( ' =?ISO-8859-1?Q?C=E9sar______?= fu bar <*****@*****.**>' )) emails.append(mimeutil.EmailAddress(' n o name @ examplE.com ')) header = mimeutil.makeEmailListHeader(emails, 'To') parsed = mimeutil.parseEmailAddresses(header.encode()) self.assertEquals(emails, parsed)
def test_flattenEmailAddresses(self): """ Test that L{xquotient.mimeutil.flattenEmailAddresses} works as expected """ self.assertEquals( mimeutil.flattenEmailAddresses( (mimeutil.EmailAddress('One <one@two>'), mimeutil.EmailAddress('two@three'))), 'One <one@two>, two@three')
def test_invoke(self): """ L{ComposeFragment.invoke} accepts a browser-generated structure representing the values in the compose form, coerces it according to the L{Parameters} it defines, and passes the result to the LiveForm callable. """ # The from addresses are web ids for FromAddress items. fromAddr = IWebTranslator(self.userStore).toWebID(self.defaultFromAddr) # Override the callable to see what happens. sent = [] expectedResult = object() def fakeSend(fromAddress, toAddresses, subject, messageBody, cc, bcc, files, draft): sent.append((fromAddress, toAddresses, subject, messageBody, cc, bcc, files, draft)) return expectedResult self.cf.callable = fakeSend toAddresses = [ mimeutil.EmailAddress(u'*****@*****.**', False), mimeutil.EmailAddress(u'*****@*****.**', False) ] subject = u'Hello World' body = u'How are you' cc = [mimeutil.EmailAddress(u'*****@*****.**', False)] bcc = [mimeutil.EmailAddress(u'*****@*****.**', False)] draft = True invokeDeferred = self.cf.invoke({ u'fromAddress': [fromAddr], u'toAddresses': [mimeutil.flattenEmailAddresses(toAddresses)], u'subject': [subject], u'messageBody': [body], u'cc': [mimeutil.flattenEmailAddresses(cc)], u'bcc': [mimeutil.flattenEmailAddresses(bcc)], u'draft': [draft] }) def cbInvoked(invokeResult): self.assertEquals( sent, [(self.defaultFromAddr, toAddresses, subject, body, cc, bcc, (), draft)]) self.assertIdentical(invokeResult, expectedResult) invokeDeferred.addCallback(cbInvoked) return invokeDeferred
def composeFragFactory(composer): return AddrPassthroughComposeFragment( composer, recipients={ 'to': [mimeutil.EmailAddress(e, False) for e in toAddresses] })
def test_redirectHeaderOrdering(self): """ Test that Resent headers get added after Received headers but before the rest. """ msgtext = """\ Received: from bob by example.com with smtp (SuparMTA 9.99) id 1BfraZ-0001D0-QA for [email protected]; Thu, 01 Jul 2004 02:46:15 +0000 received: from bob by example.com with smtp (SuparMTA 9.99) id 1BfraZ-0001D0-QA for [email protected]; Thu, 01 Jul 2004 02:46:17 +0000 From: <*****@*****.**> To: <*****@*****.**> Subject: Hi Hi """.replace('\n', '\r\n') class StubMsgFile: def open(self): return StringIO(msgtext) message = StubStoredMessageAndImplAndSource(store=self.userStore) message.__dict__['_source'] = StubMsgFile() msg = self.composer.createRedirectedMessage( self.defaultFromAddr, [mimeutil.EmailAddress(u'testuser@localhost', mimeEncoded=False)], message) m = Parser.Parser().parse(msg.impl.source.open()) self.assertEqual(len(m._headers), 9) self.assertEqual(m._headers[0][0].lower(), "received") self.assertEqual(m._headers[6][0].lower(), "from")
def test_setStatus(self): """ Test that statuses requested for parent messages get set after the created message is sent. """ # (bypass Item.__setattr__) object.__setattr__(self.composer, 'sendMessage', lambda fromA, toA, msg: None) class MsgStub: impl = MIMEPart() statuses = None def addStatus(self, status): if self.statuses is None: self.statuses = [status] else: self.statuses.append(status) parent = MsgStub() parent.impl.headers = [ Header("message-id", "<*****@*****.**>"), Header("references", "<*****@*****.**>"), Header("references", "<*****@*****.**>") ] toAddresses = [ mimeutil.EmailAddress('*****@*****.**', mimeEncoded=False) ] cf = self.msgDetail._composeSomething(toAddresses, u'Sup dood', u'A body', [], parent, REPLIED_STATUS) cf._sendOrSave(self.store.findFirst(smtpout.FromAddress), toAddresses, u'Sup dood', u'A body', [], [], [], False) self.assertEqual(parent.statuses, [REPLIED_STATUS])
def _createCCMessage(self): """ Use L{xquotient.mimebakery.createMessage} to make a message with a BCC """ return self._createMessage( cc=[mimeutil.EmailAddress('*****@*****.**', mimeEncoded=False)])
def test_createMessageWrapsLines(self): """ Ensure that the text of an outgoing message is wrapped to 78 characters and that its MIME type is 'text/plain; format=flowed'. """ self.cf._sendOrSave(fromAddress=self.defaultFromAddr, toAddresses=[ mimeutil.EmailAddress(u'[email protected]', mimeEncoded=False) ], subject=u'The subject of the message.', messageBody=u' '.join([u'some words'] * 1000), cc=[], bcc=[], files=[], draft=False) msg = self.userStore.findUnique( smtpout.DeliveryToAddress)._getMessageSource() textPart = Parser.Parser().parse(msg) self.assertEqual(textPart.get_content_type(), "text/plain") self.assertEqual(textPart.get_param("format"), "flowed") body = textPart.get_payload().decode("quoted-printable") maxLineLength = max([len(line) for line in body.split("\n")]) self.failIf(maxLineLength > 78)
def test_redirectRelatedAddresses(self): """ Test that an outgoing redirected message has the resent from/to addresses stored """ message = StubStoredMessageAndImplAndSource(store=self.userStore) RESENT_TO_ADDRESS = mimeutil.EmailAddress(u'Joe <joe@nowhere>', False) self.composer.redirect(self.defaultFromAddr, [RESENT_TO_ADDRESS], message) msg = self.userStore.findUnique(exmess.Message) def checkCorrespondents(relation, address): self.assertEquals( self.userStore.query( exmess.Correspondent, attributes.AND( exmess.Correspondent.message == msg, exmess.Correspondent.address == address, exmess.Correspondent.relation == relation)).count(), 1) checkCorrespondents(exmess.RESENT_FROM_RELATION, self.defaultFromAddr.address) checkCorrespondents(exmess.RESENT_TO_RELATION, RESENT_TO_ADDRESS.email)
def relatedAddresses(self): """ Implement L{IMessageData.relatedAddresses} by looking at relevant RFC2822 headers for sender and recipient addresses. """ for header in (u'from', u'sender', u'reply-to'): try: v = self.getHeader(header) except equotient.NoSuchHeader: continue email = mimeutil.EmailAddress(v, mimeEncoded=False) yield (exmess.SENDER_RELATION, email) break for header, relationship in [(u'cc', exmess.COPY_RELATION), (u'to', exmess.RECIPIENT_RELATION), (u'bcc', exmess.BLIND_COPY_RELATION), (u'resent-to', exmess.RESENT_TO_RELATION), (u'resent-from', exmess.RESENT_FROM_RELATION)]: try: v = self.getHeader(header) except equotient.NoSuchHeader: pass else: for addressObject in mimeutil.parseEmailAddresses( v, mimeEncoded=False): yield (relationship, addressObject)
def test_cmp(self): self.assertEquals(mimeutil.EmailAddress(' '), mimeutil.EmailAddress('')) self.assertEquals(mimeutil.EmailAddress('Fu@bAr'), mimeutil.EmailAddress(' fu @ bar ')) self.assertEquals(mimeutil.EmailAddress('bleh <Fu@bAr>'), mimeutil.EmailAddress((' bleh ', ' fu @ bar '))) self.assertNotEquals(mimeutil.EmailAddress('bleh <Fu@bAr>'), mimeutil.EmailAddress(' fu @ bar '))
def test_createMessageHonorsBCC(self): """ Sending a message through the compose UI should honor the BCC addresses we give to it """ sendMail( self.cf._savedDraft, self.composer, self.cabinet, None, None, self.defaultFromAddr, [mimeutil.EmailAddress('*****@*****.**', mimeEncoded=False)], u'', u'', [], [ mimeutil.EmailAddress('*****@*****.**', mimeEncoded=False), mimeutil.EmailAddress('*****@*****.**', mimeEncoded=False) ], u'') self.assertEquals( list( self.userStore.query( smtpout.DeliveryToAddress).getColumn('toAddress')), ['*****@*****.**', '*****@*****.**', '*****@*****.**'])
def test_notAPerson(self): """ Test L{xquotient.exmess.MessageDetail.personStanFromEmailAddress} when there is a L{xmantissa.people.Organizer}, but the email we give isn't assigned to a person """ email = mimeutil.EmailAddress('foo@bar', mimeEncoded=False) res = self.md.personStanFromEmailAddress(email) self.failUnless(isinstance(res, SenderPersonFragment))
def test_noOrganizer(self): """ Test L{xquotient.exmess.MessageDetail.personStanFromEmailAddress} when there is no L{xmantissa.people.Organizer} in the store """ self.md.organizer = None email = mimeutil.EmailAddress('foo@bar', mimeEncoded=False) stan = self.md.personStanFromEmailAddress(email) self._checkNoAddressBookStan(stan, email)
def test_createsPlaintextMessage(self): """ Test that L{mimebakery.createMessage} produces a message of type text/plain. """ msg = createMessage( self.composer, None, None, self.defaultFromAddr, [mimeutil.EmailAddress('*****@*****.**', mimeEncoded=False)], u'Sup dood', u'A body', u'', u'', u'') self.assertEqual(msg.impl.getContentType(), 'text/plain')
def test_createReplyNoMessageID(self): """ Test replying to messages with no message ID. """ parent = MsgStub() parent.impl.headers = [] msg = createMessage( self.composer, self.cabinet, parent, self.defaultFromAddr, [mimeutil.EmailAddress('*****@*****.**', mimeEncoded=False)], u'Sup dood', u'A body', (), (), u'') self.assertEqual([h.value for h in msg.impl.getHeaders('References')], [])
def test_createMessageHonorsSmarthostFromAddress(self): """ Sending a message through the Compose UI should honor the from address we give to it """ self.defaultFromAddr.address = u'*****@*****.**' msg = createMessage( self.composer, self.cabinet, None, self.defaultFromAddr, [mimeutil.EmailAddress('*****@*****.**', mimeEncoded=False)], u'Sup dood', u'A body', (), (), u'') file = msg.impl.source.open() msg = Parser.Parser().parse(file) self.assertEquals(msg["from"], '*****@*****.**')
def test_redirectNameAddr(self): """ Test that L{compose.Composer.redirect} removes the display name portion of an email address if present before trying to deliver directed mail to it """ message = StubStoredMessageAndImplAndSource(store=self.userStore) msg = self.composer.redirect( self.defaultFromAddr, [mimeutil.EmailAddress(u'Joe <joe@nowhere>', mimeEncoded=False)], message) self.assertEquals(list(self.reactor.factory.toEmail), ['joe@nowhere'])
def _createMessageWithFiles(self, files): """ Create a message with attachments corresponding to the L{xquotient.compose.File} items C{files} """ return createMessage( self.composer, self.cabinet, None, self.defaultFromAddr, [mimeutil.EmailAddress('*****@*****.**', mimeEncoded=False)], u'subject', u'body', (), (), files=list(f.storeID for f in files))
def test_aPerson(self): """ Test L{xquotient.exmess.MessageDetail.personStanFromEmailAddress} when there is a L{xmantissa.people.Organizer}, and the email we give is assigned to a person """ email = mimeutil.EmailAddress('foo@bar', mimeEncoded=False) people.EmailAddress(store=self.store, address=u'foo@bar', person=people.Person(store=self.store)) res = self.md.personStanFromEmailAddress(email) self.failUnless(isinstance(res, people.PersonFragment))
def test_createMessageNotIncoming(self): """ Verify that a message composed via the compose form does not deposit anything into the 'incoming' state, so the spam filter will not be triggered. """ sq = exmess.MailboxSelector(self.userStore) msg = createMessage( self.composer, self.cabinet, None, self.defaultFromAddr, [mimeutil.EmailAddress('*****@*****.**', mimeEncoded=False)], u'Sup dood', u'A body', u'', u'', u'') sq.refineByStatus(exmess.INCOMING_STATUS) self.assertEquals(list(sq), []) self.assertEquals(msg.hasStatus(exmess.CLEAN_STATUS), False) self.failIf(msg.shouldBeClassified)
def test_createRedirectedMessage(self): """ Test that L{compose.Composer.createRedirectedMessage} sets the right headers """ message = StubStoredMessageAndImplAndSource(store=self.userStore) msg = self.composer.createRedirectedMessage( self.defaultFromAddr, [mimeutil.EmailAddress(u'testuser@localhost', mimeEncoded=False)], message) m = Parser.Parser().parse(msg.impl.source.open()) self.assertEquals(m['Resent-To'], 'testuser@localhost') self.assertEquals(m['Resent-From'], self.defaultFromAddr.address) self.failIfEqual(m['Resent-Date'], None) self.failIfEqual(m['Resent-Message-ID'], None)
def _createMessage(self, cc=(), bcc=()): """ Use L{xquotient.mimebakery.createMessage} to make a simple message, optionally with CC/BCC headers set @param cc: addresses to CC the message to. defaults to no addresses @type cc: sequence of L{xquotient.mimeutils.EmailAddress} @param bcc: addresses to BCC the message to. defaults to no addresses @type bcc: sequence of L{xquotient.mimeutils.EmailAddress} @return: L{xquotient.exmess.Message} """ return createMessage( self.composer, self.cabinet, None, self.defaultFromAddr, [mimeutil.EmailAddress('*****@*****.**', mimeEncoded=False)], u'', u'', cc, bcc, u'')
def _parseTestCase(self, input, display, email, anyDisplayName, pseudoFormat, localpart, domain): """ Parse the given input and assert that the attributes of the resulting L{mimeutil.EmailAddress} are equal to the given values. """ e = mimeutil.EmailAddress(input) self.assertEquals(e.display, display) self.failUnless(isinstance(e.display, unicode)) self.assertEquals(e.email, email) self.failUnless(isinstance(e.email, unicode)) self.assertEquals(e.anyDisplayName(), anyDisplayName) self.failUnless(isinstance(e.anyDisplayName(), unicode)) self.assertEquals(e.pseudoFormat(), pseudoFormat) self.failUnless(isinstance(e.pseudoFormat(), unicode)) self.assertEquals(e.localpart, localpart) self.failUnless(isinstance(e.localpart, unicode)) self.assertEquals(e.domain, domain) self.failUnless(isinstance(e.domain, unicode))
def test_redirect(self): """ Test L{compose.Composer.redirect} """ message = StubStoredMessageAndImplAndSource(store=self.userStore) msg = self.composer.redirect( self.defaultFromAddr, [mimeutil.EmailAddress(u'testuser@localhost', mimeEncoded=False)], message) self.assertEquals(str(self.reactor.factory.fromEmail), self.defaultFromAddr.address) self.assertEquals(list(self.reactor.factory.toEmail), ['testuser@localhost']) m = Parser.Parser().parse( self.userStore.findUnique(exmess.Message).impl.source.open()) self.assertEquals(m['Resent-From'], self.defaultFromAddr.address) self.assertEquals(m['Resent-To'], 'testuser@localhost') self.assertEquals(message.statuses, [exmess.REDIRECTED_STATUS])
def test_createReply(self): """ Ensure that References and In-Reply-To headers are added to outgoing messages. """ parent = MsgStub() parent.impl.headers = [ Header("message-id", "<*****@*****.**>"), Header("references", "<*****@*****.**>"), Header("references", "<*****@*****.**>") ] msg = createMessage( self.composer, self.cabinet, parent, self.defaultFromAddr, [mimeutil.EmailAddress('*****@*****.**', mimeEncoded=False)], u'Sup dood', u'A body', (), (), u'') self.assertEqual([h.value for h in msg.impl.getHeaders('References')], [ "<*****@*****.**>", "<*****@*****.**>", "<*****@*****.**>" ]) self.assertEqual(msg.impl.getHeader("In-Reply-To"), "<*****@*****.**>")
def test_clientFacingAPISend(self): """ Verify that the client-facing '_sendOrSave' method, invoked by the liveform, generates a sent message when told to send the message. This is a white-box test. """ self.cf._sendOrSave(fromAddress=self.defaultFromAddr, toAddresses=[ mimeutil.EmailAddress(u'[email protected]', mimeEncoded=False) ], subject=u'The subject of the message.', messageBody=u'The body of the message.', cc=[], bcc=[], files=[], draft=False) m = self.userStore.findUnique(exmess.Message) self.assertEquals(set(m.iterStatuses()), set([exmess.UNREAD_STATUS, exmess.OUTBOX_STATUS])) nd = self.userStore.findUnique(smtpout.DeliveryToAddress) self.assertIdentical(nd.message, m)
def sendmail(self): """ Send this queued message. @param fromAddress: An optional address to use in the SMTP conversation. """ fromAddress = self.fromAddress if fromAddress is None: fromAddress = FromAddress.findDefault(self.store) if fromAddress.smtpHost: return _esmtpSendmail(fromAddress.smtpUsername, fromAddress.smtpPassword, fromAddress.smtpHost, fromAddress.smtpPort, fromAddress.address, [self.toAddress], self._getMessageSource()) else: d = self.getMailExchange( mimeutil.EmailAddress(self.toAddress, mimeEncoded=False).domain) def sendMail(mx): host = str(mx.name) log.msg(interface=iaxiom.IStatEvent, stat_messagesSent=1, userstore=self.store) return smtp.sendmail( host, fromAddress.address, [self.toAddress], # XXX self._getMessageSource()) d.addCallback(sendMail) return d