Components for dealing with e-mail are located in canonical.launchpad.mail and lp.services.mail.
For most use cases, the MailController class should be used to send e-mail from Launchpad.
Component for sending e-mail.
Parameters: |
|
---|
Add an attachment to the mail.
Parameters: |
|
---|
Example:
>>> from lp.services.mail.sendmail import MailController
>>> test_mail = MailController(
... 'Foo Bar <foo.bar@example.com>',
... ['baz@example.com'],
... 'Cool Subject',
... 'This is the content')
>>> test_mail.addAttachment(
... 'Some more info', content_type='text/plain')
>>> test_mail.send()
Each e-mail that Launchpad sent should have a rationale, for why the e-mail was sent to the receiving user. MailController expects the whole e-mail as it is to be sent, so the callsite is responsible for adding this information to the e-mail, before passing it on to MailController.
To help with this, you should create a INotificationRecipientSet instance.
Represents a set of notification recipients and rationales.
All Launchpad emails should include a footer explaining why the user is receiving the email. An INotificationRecipientSet encapsulates a list of recipients along the rationale for being on the recipients list.
The pattern for using this are as follows: email addresses in an INotificationRecipientSet are being notified because of a specific event (for instance, because a bug changed). The rationales describe why that email addresses is included in the recipient list, detailing subscription types, membership in teams and/or other possible reasons.
The set maintains the list of IPerson that will be contacted as well as the email address to use to contact them.
Add a person or sequence of person to the recipients list.
When the added person is a team without an email address, all its members emails will be added. If the person is already in the recipients list, the reson for contacting him is not changed.
Parameters: |
|
---|
Return a reason tuple containing (text, header) for an address.
The text is meant to appear in the notification footer. The header should be a short code that will appear in an X-Launchpad-Message-Rationale header for automatic filtering.
Parameter: | person_or_email – An IPerson or email address that is in the recipients list. |
---|---|
Raises UnknownRecipientError: | |
if the person or email isn’t in the recipients list. |
The NotificationRecipientSet class is a good base to use, since it provides all the necessary methods.
This class can be used to add all the people that should receive the e-mail, together with their rationale. Before sending it, you can loop through all the recipients and construct the final mail:
>>> base_mail = 'A mail.'
>>> recipients = NotificationRecipientSet()
>>> recipients.add(
... factory.makePerson(),
... 'You received this mail because you are a subscriber',
... 'subscriber')
>>> recipients.add(
... factory.makePerson(),
... 'You received this mail because you are the assignee',
... 'assignee')
>>> for person in recipients.getRecipients():
... mail_reason, header_reason = recipients.getReason(person)
... mail_with_rationale = base_mail + mail_reason
... mail_controller = MailController(
... 'Me <me@example.com',
... [person.preferredemail],
... 'A subject',
... mail_with_rationale,
... headers={'X-Launchpad-Message-Rationale': header_reason})
... mail_controller.send()
In order to receive and process mail, you either need to modify an existing mail handler, or create a new one. There is one handler for each domain, and they are registered in canonical.launchpad.mail.handlers:
>>> from canonical.launchpad.mail.handlers import mail_handlers
>>> for domain in sorted(mail_handlers._handlers.keys():
... print domain
answers.lauchpad.dev
bugs.launchpad.dev
code.launchpad.dev
specs.launchpad.dev
support.launchpad.net
Each domain is handled by an IMailHandler.
Process an e-mail message.
Parameters: |
|
---|---|
Returns: | Return False if to_address does not exist/is bad. Return True if the message was processed, successfully or unsuccessfully. This includes user or input errors. |
If you need to receive mail at a new domain, you need to create a class implementing IMailHandler, and register it with the mail_handlers object:
>>> from zope.interface import implements
>>> from canonical.launchpad.interfaces.mail import IMailHandler
>>> class ExampleHandler:
... implements(IMailHandler)
... allow_unknown_users = False
... def process(self, signed_msg, to_address, filealias, log=None):
... print "Processing mail from %s to %s." % (
... signed_msg['From'], to_address)
... return True
>>> from canonical.launchpad.mail.handlers import mail_handlers
>>> mail_handlers.add('example.com', ExampleHandler())
For testing, the process() method can be called directly, but if you need to really make sure that your handler is getting called, you can send a mail, and then call handleMail(), which will process all sent mail in tests:
>>> from lp.services.mail.sendmail import MailController
>>> test_mail = MailController(
... 'Foo Bar <foo.bar@example.com>',
... ['baz@example.com'],
... 'Cool Subject',
... 'This is the content')
>>> test_mail.send()
>>> from canonical.launchpad.mail.incoming import handleMail
>>> handleMail()
Processing mail from Foo Bar <foo.bar@example.com> to baz@example.com
See How Incoming Mail is Handled for a more in-depth explaination of how handleMail() works, and what it does.