Index: /main/waeup.kofa/trunk/src/waeup/kofa/applicants/browser.py
===================================================================
--- /main/waeup.kofa/trunk/src/waeup/kofa/applicants/browser.py	(revision 14013)
+++ /main/waeup.kofa/trunk/src/waeup/kofa/applicants/browser.py	(revision 14014)
@@ -22,4 +22,5 @@
 import grok
 import transaction
+from urllib import urlencode
 from datetime import datetime, date
 from time import time
@@ -30,4 +31,5 @@
 from hurry.workflow.interfaces import (
     IWorkflowInfo, IWorkflowState, InvalidTransitionError)
+from waeup.kofa.mandates.mandate import RefereeReportMandate
 from waeup.kofa.applicants.interfaces import (
     IApplicant, IApplicantEdit, IApplicantsRoot,
@@ -1169,4 +1171,33 @@
         return
 
+    def informReferees(self):
+        site = grok.getSite()
+        kofa_utils = getUtility(IKofaUtils)
+        ob_class = self.__implemented__.__name__.replace('waeup.kofa.','')
+        failed = ''
+        for referee in self.context.referees:
+            if referee.email_sent:
+                continue
+            mandate = RefereeReportMandate()
+            mandate.params['name'] = referee.name
+            mandate.params['email'] = referee.email
+            mandate.params[
+                'redirect_path'] = '/applicants/%s/%s/addrefereereport' % (
+                    self.context.__parent__.code,
+                    self.context.application_number)
+            site['mandates'].addMandate(mandate)
+            # Send invitation email
+            args = {'mandate_id':mandate.mandate_id}
+            mandate_url = self.url(site) + '/mandate?%s' % urlencode(args)
+            url_info = u'Report link: %s' % mandate_url
+            success = kofa_utils.inviteReferee(referee, self.context, url_info)
+            if success:
+                self.context.writeLogMessage(
+                    self, 'email sent: %s' % referee.email)
+                referee.email_sent = True
+            else:
+                failed += '%s ' % referee.email
+        return failed
+
     @action(_('Finally Submit'), warning=WARNING)
     def finalsubmit(self, **data):
@@ -1184,9 +1215,20 @@
                        type='danger')
             return
+        msg = _('Form has been submitted.')
+        # Create mandates and send emails to referees
+        if getattr(self.context, 'referees', None):
+            failed = self.informReferees()
+            if failed:
+                self.flash(
+                    _('Some invitation emails could not be sent:') + failed,
+                    type='danger')
+                return
+            msg = _('Form has been successfully submitted and '
+                    'all invitation emails were sent.')
         IWorkflowInfo(self.context).fireTransition('submit')
         # application_date is used in export files for sorting.
         # We can thus store utc.
         self.context.application_date = datetime.utcnow()
-        self.flash(_('Form has been submitted.'))
+        self.flash(msg)
         self.redirect(self.url(self.context))
         return
Index: /main/waeup.kofa/trunk/src/waeup/kofa/applicants/tests/test_browser.py
===================================================================
--- /main/waeup.kofa/trunk/src/waeup/kofa/applicants/tests/test_browser.py	(revision 14013)
+++ /main/waeup.kofa/trunk/src/waeup/kofa/applicants/tests/test_browser.py	(revision 14014)
@@ -24,4 +24,5 @@
 import tempfile
 import grok
+import logging
 from datetime import datetime
 from StringIO import StringIO
@@ -41,4 +42,5 @@
 from waeup.kofa.payments.interfaces import IPayer
 from waeup.kofa.configuration import SessionConfiguration
+from waeup.kofa.refereeentries import RefereeEntry
 from waeup.kofa.applicants.container import ApplicantsContainer
 from waeup.kofa.applicants.applicant import Applicant
@@ -1526,4 +1528,37 @@
     layer = FunctionalLayer
 
+    def setUp(self):
+        super(ApplicantRefereeReportTests, self).setUp()
+        self.setup_logging()
+        return
+
+    def tearDown(self):
+        super(ApplicantRefereeReportTests, self).tearDown()
+        self.teardown_logging()
+        return
+
+    def setup_logging(self):
+        # setup a log-handler that catches all fake mailer output
+        self.stream = StringIO()
+        handler = logging.StreamHandler(self.stream)
+        logger = logging.getLogger('test.smtp')
+        logger.addHandler(handler)
+        logger.setLevel(logging.INFO)
+        return
+
+    def get_fake_smtp_output(self):
+        # get output generated by fake mailer
+        self.stream.flush()
+        self.stream.seek(0)
+        return self.stream.read()
+
+    def teardown_logging(self):
+        # remove the log handler for fake mailer output
+        logger = logging.getLogger('test.smtp')
+        handlers = [x for x in logger.handlers]
+        for handler in handlers:
+            logger.removeHandler(handler)
+        return
+
     def test_refereereport_mandate(self):
         mandate = RefereeReportMandate()
@@ -1604,2 +1639,51 @@
         # Mandate is deleted
         self.assertEqual(len(self.app['mandates'].keys()), 0)
+
+    def test_final_submit_with_referees(self):
+        # Add two referees
+        referee1 = RefereeEntry()
+        referee2 = RefereeEntry()
+        referee1.name = u'Linda Tree'
+        referee1.email = 'linda@forest.de'
+        referee2.name = u'Otis Stone'
+        referee2.email = 'otis@stones.de'
+        self.applicant.referees = [referee1, referee2]
+        self.assertFalse(referee1.email_sent)
+        self.assertFalse(referee2.email_sent)
+        self.login()
+        IWorkflowInfo(self.applicant).fireTransition('pay')
+        self.browser.open(self.edit_path)
+        self.fill_correct_values() # fill other fields with correct values
+        image = open(SAMPLE_IMAGE, 'rb')
+        ctrl = self.browser.getControl(name='form.passport')
+        file_ctrl = ctrl.mech_control
+        file_ctrl.add_file(image, filename='myphoto.jpg')
+        self.browser.getControl("Save").click()
+        self.browser.getControl(name="confirm_passport").value = True
+        self.browser.getControl("Finally Submit").click()
+        self.assertEqual(
+            [u'Sending email from no-reply@waeup.org to linda@forest.de:',
+             u'Message:',
+             u'msg: MIME-Version: 1.0',
+             u'msg: Content-Type: text/plain; charset="us-ascii"',
+             u'msg: Content-Transfer-Encoding: 7bit',
+             u'msg: From: Administrator <no-reply@waeup.org>',
+             u'msg: To: Linda Tree <linda@forest.de>',
+             u'msg: Reply-To: Administrator <contact@waeup.org>',
+             u'msg: Subject: Request for referee report from Sample University',
+             u'msg: ',
+            ], self.get_fake_smtp_output().split('\n')[:10]
+            )
+        self.assertTrue(
+            'Application submitted' in self.browser.contents)
+        logfile = os.path.join(
+            self.app['datacenter'].storage, 'logs', 'applicants.log')
+        logcontent = open(logfile).read()
+        self.assertTrue(
+            '%s - applicants.browser.ApplicantEditFormPage - %s - '
+            'email sent: otis@stones.de' %
+            (self.applicant.applicant_id, self.applicant.applicant_id)
+            in logcontent)
+        self.assertTrue(referee1.email_sent)
+        self.assertTrue(referee2.email_sent)
+        return
Index: /main/waeup.kofa/trunk/src/waeup/kofa/utils/utils.py
===================================================================
--- /main/waeup.kofa/trunk/src/waeup/kofa/utils/utils.py	(revision 14013)
+++ /main/waeup.kofa/trunk/src/waeup/kofa/utils/utils.py	(revision 14014)
@@ -317,4 +317,29 @@
             subject, body, config)
 
+    def inviteReferee(self, referee, applicant, url_info=None):
+        """Send invitation email to referee.
+        """
+        config = grok.getSite()['configuration']
+        subject = 'Request for referee report from %s' % config.name
+        text = _(u"""Dear ${a},
+
+${c}
+
+Regards
+""")
+        from_name = config.name_admin
+        from_addr = config.email_admin
+        rcpt_name = referee.name
+        rcpt_addr = referee.email
+        text = _(text, mapping={
+            'a': rcpt_name,
+            'c': url_info})
+
+        body = translate(text, 'waeup.kofa',
+            target_language=self.PORTAL_LANGUAGE)
+        return send_mail(
+            from_name, from_addr, rcpt_name, rcpt_addr,
+            subject, body, config)
+
     def getPaymentItem(self, payment):
         """Return payment item. This method can be used to customize the
