All mails sent to Launchpad can be accessed with the IMailBox utility.
There are three different IMailBox utilities available. One, TestMailBox,
is configured for tests, and operates on stub.test_emails. This means
that every mail you send in a test can be accessed by using this mail
box.
There's also an IMailBox which interfaces with a POP3 server. It can be
configured in ZCML with:
It also supports POP3 over ssl:
The third is the DirectoryMailBox and can be configured to operate for
interactive testing of the email processing. There is an example config
located at: configs/development/directory-testing-mailbox.zcml.example. To
get this picked up by the process email cronscript, you need to copy it to the
directory above the working tree and call it +testing-mailbox.zcml (actually
you could call it anything that matches +*.zcml loaded from script.zcml).
There is a helper function create_mail_for_directoryMailBox that can be
run with something like this::
make harness
from lp.testing import mail
mail.create_mail_for_directoryMailBox(
'me@example.com',
'new@bugs.launchpad.net',
'help',
'message body',
)
Let's look at the one we use in tests:
>>> from lp.services.mail.mailbox import IMailBox
>>> mailbox = getUtility(IMailBox)
Now it's empty, so let's add some mails to it by using simple_sendmail:
>>> import transaction
>>> from lp.services.mail.sendmail import simple_sendmail
>>> msgid = simple_sendmail('test@canonical.com',
... '123@bugs.canonical.com',
... 'Hello',
... 'bla bla bla',
... headers={'Message-ID': ''})
>>> transaction.commit()
>>> msgid = simple_sendmail('test@canonical.com',
... '456@bugs.canonical.com',
... 'Hello',
... 'bla bla bla',
... headers={'Message-ID': ''})
>>> transaction.commit()
Before we can use it, it has to be opened.
>>> mailbox.open()
To prevent two threads opening it the same time, if it's already open,
we can't open it again:
>>> mailbox.open()
Traceback (most recent call last):
...
MailBoxError: The mail box is already open.
There's only one mail in the mail box, and it's the same as we sent
before:
>>> mails = list(mailbox.items())
>>> len(mails)
2
>>> id, raw_mail = mails[0]
>>> import email
>>> mail = email.message_from_string(raw_mail)
>>> print mail['Message-ID']
When we're done using the mail box we have to close it:
>>> mailbox.close()
Since we didn't delete the mail, it's still in there:
>>> mailbox.open()
>>> mails = list(mailbox.items())
>>> len(mails)
2
>>> id, raw_mail = mails[0]
>>> mail = email.message_from_string(raw_mail)
>>> print mail['Message-ID']
Let's delete all mails in the mail box:
>>> for id, mail in mailbox.items():
... mailbox.delete(id)
>>> list(mailbox.items())
[]
If we try to delete a mail that doesn't exist we get an error:
>>> mailbox.delete(-1)
Traceback (most recent call last):
...
MailBoxError: No such id: -1
>>> mailbox.close()