Esempio n. 1
0
 def options(self):
     # Options to pass to the templates.  We used to return an empty
     # dictionary by default, but we might as well return something useful
     # for most cases.
     context = aq_inner(self.context)
     portal = getSite()
     fromName = portal.getProperty('email_from_name', '')
     portal_membership = getToolByName(portal, 'portal_membership')
     member = portal_membership.getAuthenticatedMember()
     memberInfo = portal_membership.getMemberInfo(member.getUserName())
     stateChanger = member.getUserName()
     if memberInfo:
         stateChanger = memberInfo['fullname'] or stateChanger
     # We expect to be called with an issue as context, but perhaps there
     # are other use cases, like a tracker or a brain or a response.
     # Get hold of the tracker if we can.
     if IIssue.providedBy(context):
         tracker = context.getTracker()
     elif ITracker.providedBy(context):
         tracker = context
     else:
         # This would be strange.
         tracker = None
     if tracker is None:
         tracker_title = ''
     else:
         tracker_title = tracker.title_or_id()
     mapping = dict(issue_title=su(context.title_or_id()),
                    tracker_title=su(tracker_title),
                    response_author=su(stateChanger),
                    issue_url=su(context.absolute_url()),
                    from_name=su(fromName))
     return mapping
Esempio n. 2
0
 def options(self):
     # Options to pass to the templates.  We used to return an empty
     # dictionary by default, but we might as well return something useful
     # for most cases.
     context = aq_inner(self.context)
     portal = getSite()
     fromName = portal.getProperty('email_from_name', '')
     portal_membership = getToolByName(portal, 'portal_membership')
     member = portal_membership.getAuthenticatedMember()
     memberInfo = portal_membership.getMemberInfo(member.getUserName())
     stateChanger = member.getUserName()
     if memberInfo:
         stateChanger = memberInfo['fullname'] or stateChanger
     # We expect to be called with an issue as context, but perhaps there
     # are other use cases, like a tracker or a brain or a response.
     # Get hold of the tracker if we can.
     if IIssue.providedBy(context):
         tracker = context.getTracker()
     elif ITracker.providedBy(context):
         tracker = context
     else:
         # This would be strange.
         tracker = None
     if tracker is None:
         tracker_title = ''
     else:
         tracker_title = tracker.title_or_id()
     mapping = dict(
         issue_title=su(context.title_or_id()),
         tracker_title=su(tracker_title),
         response_author=su(stateChanger),
         issue_url=su(context.absolute_url()),
         from_name=su(fromName))
     return mapping
    def plain(self):
        context = aq_inner(self.context)
        portal = getSite()
        fromName = portal.getProperty("email_from_name", "")
        portal_membership = getToolByName(portal, "portal_membership")
        member = portal_membership.getAuthenticatedMember()
        memberInfo = portal_membership.getMemberInfo(member.getUserName())
        stateChanger = member.getUserName()
        if memberInfo:
            stateChanger = memberInfo["fullname"] or stateChanger
        mail_text = _(
            "email_task_closed_template",
            u"""The task **${task_title}** has been marked as resolved by **${response_author}**.
Please visit the task and either confirm that it has been
satisfactorily resolved or re-open it.

Response Information
--------------------

Task
  ${task_title} (${task_url})


* This is an automated email, please do not reply - ${from_name}""",
            mapping=dict(
                task_title=su(context.title),
                response_author=su(stateChanger),
                task_url=su(context.absolute_url()),
                from_name=su(fromName),
            ),
        )

        # Translate the body text
        mail_text = translate(mail_text, "s17.taskmanager", context=self.request)
        return mail_text
Esempio n. 4
0
    def options(self):
        mapping = super(NewResponseMail, self).options()
        context = aq_inner(self.context)
        folder = IResponseContainer(context)
        response = folder[self.response_id]
        responseText = su(response.text)
        paras = responseText.splitlines()

        # Indent the response details so they are correctly
        # interpreted as a literal block after the double colon behind
        # the 'Response Details' header.  This only really matters
        # when someone interprets this as reStructuredText though.
        responseDetails = u'\n\n'.join([wrapper.fill(p) for p in paras])

        changes = []
        for change in response.changes:
            before = su(change.get('before'))
            after = su(change.get('after'))
            name = su(change.get('name'))
            # Some changes are workflow changes, which can be translated.
            # Note that workflow changes are in the plone domain.
            before = translate(before, 'plone', context=self.request)
            after = translate(after, 'plone', context=self.request)
            name = translate(name, 'Poi', context=self.request)
            changes.append(dict(name=name, before=before, after=after))
        if response.attachment:
            attachment_id = getattr(response.attachment, 'filename', u'')
        else:
            attachment_id = u''

        mapping['response_details'] = responseDetails
        mapping['changes'] = changes
        mapping['attachment_id'] = attachment_id
        return mapping
Esempio n. 5
0
    def options(self):
        mapping = super(NewResponseMail, self).options()
        context = aq_inner(self.context)
        folder = IResponseContainer(context)
        response = folder[self.response_id]
        responseText = su(response.text)
        paras = responseText.splitlines()

        # Indent the response details so they are correctly
        # interpreted as a literal block after the double colon behind
        # the 'Response Details' header.  This only really matters
        # when someone interprets this as reStructuredText though.
        responseDetails = u'\n\n'.join([wrapper.fill(p) for p in paras])

        changes = []
        for change in response.changes:
            before = su(change.get('before'))
            after = su(change.get('after'))
            name = su(change.get('name'))
            # Some changes are workflow changes, which can be translated.
            # Note that workflow changes are in the plone domain.
            before = translate(before, 'plone', context=self.request)
            after = translate(after, 'plone', context=self.request)
            name = translate(name, 'Poi', context=self.request)
            changes.append(dict(name=name, before=before, after=after))
        if response.attachment:
            attachment_id = getattr(response.attachment, 'filename', u'')
        else:
            attachment_id = u''

        mapping['response_details'] = responseDetails
        mapping['changes'] = changes
        mapping['attachment_id'] = attachment_id
        return mapping
 def subject(self):
     context = aq_inner(self.context)
     subject = _(
         "email_task_closed_subject_template",
         u"[Resolved #${task_title}]",
         mapping=dict(task_title=su(context.title)),
     )
     # Make the subject unicode and translate it too.
     subject = su(subject)
     subject = translate(subject, "s17.taskmanager", context=self.request)
     return subject
Esempio n. 7
0
 def subject(self):
     context = aq_inner(self.context)
     tracker = context.getTracker()
     subject = _('poi_email_new_response_subject_template',
                 u"[${tracker_title}] #${issue_id} - Re: ${issue_title}",
                 mapping=dict(tracker_title=su(tracker.Title()),
                              issue_id=su(context.getId()),
                              issue_title=su(context.Title())))
     # Ensure that the subject is unicode and translate it too.
     subject = su(subject)
     subject = translate(subject, 'Poi', context=self.request)
     return subject
Esempio n. 8
0
 def subject(self):
     context = aq_inner(self.context)
     tracker = context.getTracker()
     subject = _(
         'poi_email_issue_resolved_subject_template',
         u"[${tracker_title}] Resolved #${issue_id} - ${issue_title}",
         mapping=dict(tracker_title=su(tracker.Title()),
                      issue_id=su(context.getId()),
                      issue_title=su(context.Title())))
     # Make the subject unicode and translate it too.
     subject = su(subject)
     subject = translate(subject, 'Poi', context=self.request)
     return subject
Esempio n. 9
0
 def subject(self):
     context = aq_inner(self.context)
     tracker = context.getTracker()
     subject = _(
         'poi_email_new_response_subject_template',
         u"[${tracker_title}] #${issue_id} - Re: ${issue_title}",
         mapping=dict(
             tracker_title=su(tracker.Title()),
             issue_id=su(context.getId()),
             issue_title=su(context.Title())))
     # Ensure that the subject is unicode and translate it too.
     subject = su(subject)
     subject = translate(subject, 'Poi', context=self.request)
     return subject
Esempio n. 10
0
 def subject(self):
     context = aq_inner(self.context)
     tracker = context.getTracker()
     subject = _(
         'poi_email_issue_resolved_subject_template',
         u"[${tracker_title}] Resolved #${issue_id} - ${issue_title}",
         mapping=dict(
             tracker_title=su(tracker.getExternalTitle()),
             issue_id=su(context.getId()),
             issue_title=su(context.Title())))
     # Make the subject unicode and translate it too.
     subject = su(subject)
     subject = translate(subject, 'Poi', context=self.request)
     return subject
Esempio n. 11
0
    def options(self):
        context = aq_inner(self.context)
        folder = IResponseContainer(context)
        response = folder[self.response_id]
        tracker = aq_parent(context)

        portal_url = getToolByName(context, 'portal_url')
        portal = portal_url.getPortalObject()
        portal_membership = getToolByName(portal, 'portal_membership')
        fromName = su(portal.getProperty('email_from_name', ''))

        creator = response.creator
        creatorInfo = portal_membership.getMemberInfo(creator)
        if creatorInfo and creatorInfo['fullname']:
            responseAuthor = creatorInfo['fullname']
        else:
            responseAuthor = creator
        responseAuthor = su(responseAuthor)

        responseText = su(response.text)
        paras = responseText.splitlines()

        # Indent the response details so they are correctly
        # interpreted as a literal block after the double colon behind
        # the 'Response Details' header.  This only really matters
        # when someone interprets this as reStructuredText though.
        # FIXME: wrong for html mail  (maybe also in above 2 lines of code)
        responseDetails = u'\n\n'.join([wrapper.fill(p) for p in paras])

        changes = []
        for change in response.changes:
            before = su(change.get('before'))
            after = su(change.get('after'))
            name = su(change.get('name'))
            # Some changes are workflow changes, which can be translated.
            # Note that workflow changes are in the plone domain.
            before = translate(before, 'plone', context=self.request)
            after = translate(after, 'plone', context=self.request)
            name = translate(name, 'Poi', context=self.request)
            changes.append(dict(name=name, before=before, after=after))
        if response.attachment:
            attachment_id = response.attachment.getId()
        else:
            attachment_id = u''

        mapping = dict(
            issue_title=su(context.title_or_id()),
            tracker_title=su(tracker.title_or_id()),
            response_author=responseAuthor,
            response_details=responseDetails,
            issue_url=su(context.absolute_url()),
            changes=changes,
            from_name=fromName,
            attachment_id=attachment_id)
        return mapping
Esempio n. 12
0
    def options(self):
        context = aq_inner(self.context)
        folder = IResponseContainer(context)
        response = folder[self.response_id]
        tracker = aq_parent(context)

        portal_url = getToolByName(context, 'portal_url')
        portal = portal_url.getPortalObject()
        portal_membership = getToolByName(portal, 'portal_membership')
        fromName = su(portal.getProperty('email_from_name', ''))

        creator = response.creator
        creatorInfo = portal_membership.getMemberInfo(creator)
        if creatorInfo and creatorInfo['fullname']:
            responseAuthor = creatorInfo['fullname']
        else:
            responseAuthor = creator
        responseAuthor = su(responseAuthor)

        responseText = su(response.text)
        paras = responseText.splitlines()

        # Indent the response details so they are correctly
        # interpreted as a literal block after the double colon behind
        # the 'Response Details' header.  This only really matters
        # when someone interprets this as reStructuredText though.
        responseDetails = u'\n\n'.join([wrapper.fill(p) for p in paras])

        changes = []
        for change in response.changes:
            before = su(change.get('before'))
            after = su(change.get('after'))
            name = su(change.get('name'))
            # Some changes are workflow changes, which can be translated.
            # Note that workflow changes are in the plone domain.
            before = translate(before, 'plone', context=self.request)
            after = translate(after, 'plone', context=self.request)
            name = translate(name, 'Poi', context=self.request)
            changes.append(dict(name=name, before=before, after=after))
        if response.attachment:
            attachment_id = response.attachment.getId()
        else:
            attachment_id = u''

        mapping = dict(issue_title=su(context.title_or_id()),
                       tracker_title=su(tracker.title_or_id()),
                       response_author=responseAuthor,
                       response_details=responseDetails,
                       issue_url=su(context.absolute_url()),
                       changes=changes,
                       from_name=fromName,
                       attachment_id=attachment_id)
        return mapping
    def prepare_email_message(self):
        plain = self.plain
        if not plain:
            return None

        # We definitely want unicode at this point.
        plain = su(plain)

        # We must choose the body charset manually.  Note that the
        # goal and effect of this loop is to determine the
        # body_charset.
        for body_charset in "US-ASCII", get_charset(), "UTF-8":
            try:
                plain.encode(body_charset)
            except UnicodeEncodeError:
                pass
            else:
                break
            # Encoding should work now; let's replace errors just in case.
        plain = plain.encode(body_charset, "replace")

        text_part = MIMEText(plain, "plain", body_charset)

        email_msg = MIMEMultipart("alternative")
        email_msg.epilogue = ""
        email_msg.attach(text_part)
        return email_msg
Esempio n. 14
0
    def options(self):
        mapping = super(NewIssueMail, self).options()
        context = aq_inner(self.context)
        portal = getSite()
        portal_membership = getToolByName(portal, 'portal_membership')
        issueCreator = context.Creator()
        issueCreatorInfo = portal_membership.getMemberInfo(issueCreator)
        issueAuthor = issueCreator
        if issueCreatorInfo:
            issueAuthor = issueCreatorInfo['fullname'] or issueCreator

        issueText = context.getDetails(mimetype="text/x-web-intelligent")
        paras = issueText.splitlines()
        issueDetails = '\n\n'.join([wrapper.fill(p) for p in paras])
        mapping['issue_author'] = su(issueAuthor)
        mapping['issue_details'] = su(issueDetails)
        return mapping
Esempio n. 15
0
 def options(self):
     context = aq_inner(self.context)
     portal = getSite()
     fromName = portal.getProperty('email_from_name', '')
     portal_membership = getToolByName(portal, 'portal_membership')
     member = portal_membership.getAuthenticatedMember()
     memberInfo = portal_membership.getMemberInfo(member.getUserName())
     stateChanger = member.getUserName()
     if memberInfo:
         stateChanger = memberInfo['fullname'] or stateChanger
     tracker = context.getTracker()
     mapping = dict(issue_title=su(context.title_or_id()),
                    tracker_title=su(tracker.title_or_id()),
                    response_author=su(stateChanger),
                    issue_url=su(context.absolute_url()),
                    from_name=su(fromName))
     return mapping
    def plain(self):
        context = aq_inner(self.context)
        portal = getSite()
        fromName = portal.getProperty("email_from_name", "")
        portal_membership = getToolByName(portal, "portal_membership")
        taskCreator = context.Creator()
        taskCreatorInfo = portal_membership.getMemberInfo(taskCreator)
        taskAuthor = taskCreator
        if taskCreatorInfo:
            taskAuthor = taskCreatorInfo["fullname"] or taskCreator

        taskText = context.text
        if taskText:
            paras = taskText.raw.splitlines()
            taskDetails = "\n\n".join([wrapper.fill(p) for p in paras])
        else:
            taskDetails = _("email_null_task_details", u"""No details in the task """)
        mail_text = _(
            "email_new_task_template",
            u"""A new task has been submitted by **${task_author}**.

Task Information
----------------

Task
  ${task_title} (${task_url})


**Task Details**::

${task_details}


* This is an automated email, please do not reply - ${from_name}""",
            mapping=dict(
                task_title=su(context.title),
                task_author=su(taskAuthor),
                task_details=su(taskDetails),
                task_url=su(context.absolute_url()),
                from_name=su(fromName),
            ),
        )
        # Translate the body text
        mail_text = translate(mail_text, "s17.taskmanager", context=self.request)
        return mail_text
Esempio n. 17
0
 def options(self):
     context = aq_inner(self.context)
     portal = getSite()
     fromName = portal.getProperty('email_from_name', '')
     portal_membership = getToolByName(portal, 'portal_membership')
     member = portal_membership.getAuthenticatedMember()
     memberInfo = portal_membership.getMemberInfo(member.getUserName())
     stateChanger = member.getUserName()
     if memberInfo:
         stateChanger = memberInfo['fullname'] or stateChanger
     tracker = context.getTracker()
     mapping = dict(
         issue_title=su(context.title_or_id()),
         tracker_title=su(tracker.title_or_id()),
         response_author=su(stateChanger),
         issue_url=su(context.absolute_url()),
         from_name=su(fromName))
     return mapping
 def subject(self):
     context = aq_inner(self.context)
     subject = _(
         "email_new_response_subject_template", u"Re: ${task_title}", mapping=dict(task_title=su(context.title))
     )
     # Ensure that the subject is unicode and translate it too.
     subject = su(subject)
     subject = translate(subject, "s17.taskmanager", context=self.request)
     return subject
Esempio n. 19
0
    def prepare_email_message(self):
        plain = self.plain
        html = self.html
        if not plain and not html:
            return None

        # We definitely want unicode at this point.
        plain = utils.su(plain)
        html = utils.su(html)

        # We must choose the body charset manually.  Note that the
        # goal and effect of this loop is to determine the
        # body_charset.
        for body_charset in 'US-ASCII', utils.get_charset(), 'UTF-8':
            try:
                plain.encode(body_charset)
                html.encode(body_charset)
            except UnicodeEncodeError:
                pass
            else:
                break
        # Encoding should work now; let's replace errors just in case.
        plain = plain.encode(body_charset, 'replace')
        html = html.encode(body_charset, 'xmlcharrefreplace')

        text_part = MIMEText(plain, 'plain', body_charset)
        html_part = MIMEText(html, 'html', body_charset)

        # No sense in sending plain text and html when we only have
        # one of those:
        if not plain:
            return html_part
        if not html:
            return text_part

        # Okay, we send both plain text and html
        email_msg = MIMEMultipart('alternative')
        email_msg.epilogue = ''
        email_msg.attach(text_part)
        email_msg.attach(html_part)
        return email_msg
Esempio n. 20
0
    def prepare_email_message(self):
        plain = self.plain
        html = self.html
        if not plain and not html:
            return None

        # We definitely want unicode at this point.
        plain = utils.su(plain)
        html = utils.su(html)

        # We must choose the body charset manually.  Note that the
        # goal and effect of this loop is to determine the
        # body_charset.
        for body_charset in 'US-ASCII', utils.get_charset(), 'UTF-8':
            try:
                plain.encode(body_charset)
                html.encode(body_charset)
            except UnicodeEncodeError:
                pass
            else:
                break
        # Encoding should work now; let's replace errors just in case.
        plain = plain.encode(body_charset, 'replace')
        html = html.encode(body_charset, 'xmlcharrefreplace')

        text_part = MIMEText(plain, 'plain', body_charset)
        html_part = MIMEText(html, 'html', body_charset)

        # No sense in sending plain text and html when we only have
        # one of those:
        if not plain:
            return html_part
        if not html:
            return text_part

        # Okay, we send both plain text and html
        email_msg = MIMEMultipart('alternative')
        email_msg.epilogue = ''
        email_msg.attach(text_part)
        email_msg.attach(html_part)
        return email_msg
Esempio n. 21
0
    def options(self):
        mapping = super(NewIssueMail, self).options()
        context = aq_inner(self.context)
        portal = getSite()
        portal_membership = getToolByName(portal, 'portal_membership')
        issueCreator = context.Creator()
        issueCreatorInfo = portal_membership.getMemberInfo(issueCreator)
        issueAuthor = issueCreator
        if issueCreatorInfo:
            issueAuthor = issueCreatorInfo['fullname'] or issueCreator

        issueText = context.details.output
        paras = issueText.splitlines()
        issueDetails = '\n'.join([wrapper.fill(p) for p in paras])
        transformer = ITransformer(context)
        issuePlainText = transformer(context.details, 'text/plain')
        issuePlainDetails = '\n'.join([wrapper.fill(p) for p in paras])
        paras = issuePlainText.splitlines()
        mapping['issue_author'] = su(issueAuthor)
        mapping['issue_details'] = su(issueDetails)
        mapping['issue_plain_details'] = su(issuePlainDetails)
        return mapping
Esempio n. 22
0
    def options(self):
        mapping = super(NewIssueMail, self).options()
        context = aq_inner(self.context)
        portal = getSite()
        portal_membership = getToolByName(portal, 'portal_membership')
        issueCreator = context.Creator()
        issueCreatorInfo = portal_membership.getMemberInfo(issueCreator)
        issueAuthor = issueCreator
        if issueCreatorInfo:
            issueAuthor = issueCreatorInfo['fullname'] or issueCreator

        issueText = context.details.output
        paras = issueText.splitlines()
        issueDetails = '\n'.join([wrapper.fill(p) for p in paras])
        transformer = ITransformer(context)
        issuePlainText = transformer(context.details, 'text/plain')
        issuePlainDetails = '\n'.join([wrapper.fill(p) for p in paras])
        paras = issuePlainText.splitlines()
        mapping['issue_author'] = su(issueAuthor)
        mapping['issue_details'] = su(issueDetails)
        mapping['issue_plain_details'] = su(issuePlainDetails)
        return mapping
Esempio n. 23
0
    def options(self):
        context = aq_inner(self.context)
        portal = getSite()
        fromName = portal.getProperty('email_from_name', '')
        portal_membership = getToolByName(portal, 'portal_membership')
        issueCreator = context.Creator()
        issueCreatorInfo = portal_membership.getMemberInfo(issueCreator)
        issueAuthor = issueCreator
        if issueCreatorInfo:
            issueAuthor = issueCreatorInfo['fullname'] or issueCreator

        issueText = context.getDetails(mimetype="text/x-web-intelligent")
        paras = issueText.splitlines()
        issueDetails = '\n\n'.join([wrapper.fill(p) for p in paras])
        tracker = context.getTracker()
        mapping = dict(issue_title=su(context.title_or_id()),
                       tracker_title=su(tracker.title_or_id()),
                       issue_author=su(issueAuthor),
                       issue_details=su(issueDetails),
                       issue_url=su(context.absolute_url()),
                       from_name=su(fromName))
        return mapping
Esempio n. 24
0
    def options(self):
        context = aq_inner(self.context)
        portal = getSite()
        fromName = portal.getProperty('email_from_name', '')
        portal_membership = getToolByName(portal, 'portal_membership')
        issueCreator = context.Creator()
        issueCreatorInfo = portal_membership.getMemberInfo(issueCreator)
        issueAuthor = issueCreator
        if issueCreatorInfo:
            issueAuthor = issueCreatorInfo['fullname'] or issueCreator

        issueText = context.getDetails(mimetype="text/x-web-intelligent")
        paras = issueText.splitlines()
        issueDetails = '\n\n'.join([wrapper.fill(p) for p in paras])
        tracker = context.getTracker()
        mapping = dict(
            issue_title=su(context.title_or_id()),
            tracker_title=su(tracker.title_or_id()),
            issue_author=su(issueAuthor),
            issue_details=su(issueDetails),
            issue_url=su(context.absolute_url()),
            from_name=su(fromName))
        return mapping
    def plain(self):
        """When a response is created, send a notification email to all
        tracker managers
        """
        response_id = self.request.get("response_id", -1)
        context = aq_inner(self.context)
        folder = IResponseContainer(context)
        response = folder[response_id]

        portal_url = getToolByName(context, "portal_url")
        portal = portal_url.getPortalObject()
        portal_membership = getToolByName(portal, "portal_membership")
        fromName = su(portal.getProperty("email_from_name", ""))

        creator = response.creator
        creatorInfo = portal_membership.getMemberInfo(creator)
        if creatorInfo and creatorInfo["fullname"]:
            responseAuthor = creatorInfo["fullname"]
        else:
            responseAuthor = creator
        responseAuthor = su(responseAuthor)

        responseText = su(response.text)
        paras = responseText.splitlines()

        # Indent the response details so they are correctly interpreted as
        # a literal block after the double colon behind the 'Response
        # Details' header.
        wrapper = textwrap.TextWrapper(initial_indent=u"    ", subsequent_indent=u"    ")
        responseDetails = u"\n\n".join([wrapper.fill(p) for p in paras])

        if responseDetails:
            header = _("heading_response_details", u"Response Details")
            header = translate(header, "s17.taskmanager", context=self.request)
            responseDetails = u"**%s**::\n\n\n%s" % (header, responseDetails)

        changes = u""
        for change in response.changes:
            before = su(change.get("before"))
            after = su(change.get("after"))
            name = su(change.get("name"))
            # Some changes are workflow changes, which can be translated.
            # Note that workflow changes are in the plone domain.
            before = translate(before, "s17.taskmanager", context=self.request)
            after = translate(after, "s17.taskmanager", context=self.request)
            name = translate(name, "s17.taskmanager", context=self.request)
            changes += u"- %s: %s -> %s\n" % (name, before, after)

        mail_text = _(
            "email_new_response_template",
            u"""A new response has been given to the task **${task_title}**
by **${response_author}**.

Response Information
--------------------

Task
  ${task_title} (${task_url})

${changes}

${response_details}

* This is an automated email, please do not reply - ${from_name}""",
            mapping=dict(
                task_title=su(context.title),
                response_author=responseAuthor,
                response_details=responseDetails,
                task_url=su(context.absolute_url()),
                changes=changes,
                from_name=fromName,
            ),
        )
        mail_text = translate(mail_text, "s17.taskmanager", context=self.request)
        return mail_text