The buildbot can also send email when builds finish. The most common use of this is to tell developers when their change has caused the build to fail. It is also quite common to send a message to a mailing list (usually named “builds” or similar) about every build.
The MailNotifier status target is used to accomplish this. You
configure it by specifying who mail should be sent to, under what
circumstances mail should be sent, and how to deliver the mail. It can
be configured to only send out mail for certain builders, and only
send messages when the build fails, or when the builder transitions
from success to failure. It can also be configured to include various
build logs in each message.
   
By default, the message will be sent to the Interested Users list (see Doing Things With Users), which includes all developers who made changes in the build. You can add additional recipients with the extraRecipients argument.
Each MailNotifier sends mail to a single set of recipients. To send different kinds of mail to different recipients, use multiple MailNotifiers.
The following simple example will send an email upon the completion of each build, to just those developers whose Changes were included in the build. The email contains a description of the Build, its results, and URLs where more information can be obtained.
     from buildbot.status.mail import MailNotifier
     mn = MailNotifier(fromaddr="buildbot@example.org", lookup="example.org")
     c['status'].append(mn)
   To get a simple one-message-per-build (say, for a mailing list), use
the following form instead. This form does not send mail to individual
developers (and thus does not need the lookup= argument,
explained below), instead it only ever sends mail to the “extra
recipients” named in the arguments:
     mn = MailNotifier(fromaddr="buildbot@example.org",
                       sendToInterestedUsers=False,
                       extraRecipients=['listaddr@example.org'])
   If your SMTP host only allows you to send emails if you authenticate over TLS. This can also be done:
     mn = MailNotifier(fromaddr="myuser@gmail.com",
                       sendToInterestedUsers=False,
                       extraRecipients=["listaddr@example.org"],
                       useTls=True, relayhost="smtp.gmail.com", smtpPort=587,
                       smtpUser="myuser@gmail.com", smtpPassword="mypassword")
   In some cases it is desirable to have different information then what is
provided in a standard MailNotifier message. For this purpose MailNotifier
provides the argument messageFormatter (a function) which allows for the
creation of messages with unique content.
   
For example, if only short emails are desired (e.g., for delivery to phones)
     from buildbot.status.builder import Results
     def messageFormatter(mode, name, build, results, master_status):
         result = Results[results]
     
         text = list()
         text.append("STATUS: %s" % result.title())
         return {
             'body' : "\n".join(text),
             'type' : 'plain'
         }
     
     mn = MailNotifier(fromaddr="buildbot@example.org",
                       sendToInterestedUsers=False,
                       mode='problem',
                       extraRecipients=['listaddr@example.org'],
                       messageFormatter=messageFormatter)
   Another example of a function delivering a customized html email containing the last 80 lines of logs of a failing build step is given below:
     from buildbot.status.builder import Results
     
     def message_formatter(mode, name, build, results, master_status):
         """Provide a customized message to BuildBot's MailNotifier.
     
         The last 80 lines of the log are provided as well as the changes
         relevant to the build.  Message content is formatted as html.
         """
         result = Results[results]
     
         limit_lines = 80
         text = list()
         text.append('<h4>Build status: %s</h4>' % result.upper())
         text.append("Buildslave for this Build: <b>%s</b>" % build.getSlavename())
         text.append('<br>')
         if master_status.getURLForThing(build):
             text.append('Complete logs for all build steps: <a href="%s">%s</a>'
                         % (master_status.getURLForThing(build),
                            master_status.getURLForThing(build))
                         )
         text.append('<br>')
         text.append("Build Reason: %s" % build.getReason())
         text.append('<br>')
     
         source = ""
         ss = build.getSourceStamp()
         if ss.branch:
             source += "[branch %s] " % ss.branch
         if ss.revision:
             source +=  ss.revision
         else:
             source += "HEAD"
         if ss.patch:
             source += " (plus patch)"
         text.append("Build Source Stamp: <b>%s</b>" % source)
         text.append('<br>')
         text.append("Blamelist: %s" % ",".join(build.getResponsibleUsers()))
         if ss.changes:
             text.append('<h4>Recent Changes:</h4>')
             text.extend([c.asHTML() for c in ss.changes])
     
         logs = list()
         for log in build.getLogs():
             log_name = "%s.%s" % (log.getStep().getName(), log.getName())
             log_status, dummy = log.getStep().getResults()
             log_body = log.getText().splitlines() # Note: can be VERY LARGE
             log_url = '%s/steps/%s/logs/%s' % (master_status.getURLForThing(build),
                                                log.getStep().getName(),
                                                log.getName())
             logs.append((log_name, log_url, log_body, log_status))
     
         name, url, content, logstatus = logs[-1]
     
         text.append('<i>Detailed log of last build step:</i> <a href="%s">%s</a>'
                     % (url, url))
         text.append('<br>')
         text.append('<h4>Last %d lines of "%s":</h4>' % (limit_lines, name))
         text.append('<p>')
         text.append('<br>'.join([line for line in
                                  content[len(content)-limit_lines:]]))
         text.append('</p>')
         text.append('<br><br>')
         text.append('<b>-The BuildBot</b>')
         return {
             'body': "\n".join(text),
             'type': 'html'
             }
     
     mn = MailNotifier(fromaddr="buildbot@example.org",
                       sendToInterestedUsers=False,
                       mode='failing',
                       extraRecipients=['listaddr@example.org'],
                       messageFormatter=message_formatter)
   fromaddrsendToInterestedUsersextraRecipientssubject%(builder)s will be replaced with the name of the builder which
provoked the message.
     modeallchangefailingpassingproblembuilderscategoriesaddLogsaddPatchrelayhostsmtpPortuseTlsTrue (default is False)
MailNotifier sends emails using TLS and authenticates with the
ralayhost. When using TLS the arguments smtUser and
smtpPassword must also be specified.
     smtpUserrelayhost. Only used when useTls is True.
     smtpPasswordrelayhost. Only used when useTls is True.
     lookupIEmailLookup). Object which provides
IEmailLookup, which is responsible for mapping User names (which come
from the VC system) into valid email addresses. If not provided, the
notifier will only be able to send mail to the addresses in the
extraRecipients list. Most of the time you can use a simple Domain
instance. As a shortcut, you can pass as string: this will be treated
as if you had provided Domain(str). For example,
lookup='twistedmatrix.com' will allow mail to be sent to all
developers whose SVN usernames match their twistedmatrix.com account
names. See buildbot/status/mail.py for more details.
     messageFormattermessageFormatter function takes the mail mode (mode), builder
name (name), the build status (build), the result code
(results), and the BuildMaster status (master_status).  It
returns a dictionary. The body key gives a string that is the complete
text of the message. The type key is the message type ('plain' or
'html'). The 'html' type should be used when generating an HTML message.  The
subject key is optional, but gives the subject for the email.
     extraHeadersAs a help to those writing messageFormatter functions, the following
table describes how to get some useful pieces of information from the various
status objects:
     
name
master_status.getProjectName()
mode (one of all, failing, problem, change, passing)
          from buildbot.status.builder import Results
          result_str = Results[results]
          # one of 'success', 'warnings', 'failure', 'skipped', or 'exception'
     master_status.getURLForThing(build)
master_status.getBuildbotURL()
build.getText()
build.getProperties() (a Properties instance)
build.getSlavename()
build.getReason()
build.getResponsibleUsers()
          ss = build.getSourceStamp()
          if ss:
              branch = ss.branch
              revision = ss.revision
              patch = ss.patch
              changes = ss.changes # list
     A change object has the following useful information:
whorevisionbranchwhenfilescommentsChange methods asText and asHTML return a list of strings with
the above information formatted. 
          logs = list()
          for log in build.getLogs():
              log_name = "%s.%s" % (log.getStep().getName(), log.getName())
              log_status, dummy = log.getStep().getResults()
              log_body = log.getText().splitlines() # Note: can be VERY LARGE
              log_url = '%s/steps/%s/logs/%s' % (master_status.getURLForThing(build),
                                                 log.getStep().getName(),
                                                 log.getName())
              logs.append((log_name, log_url, log_body, log_status))