source: mailtotracplugin/0.12/plugin/mail2trac/email2trac.py

Last change on this file was 16530, checked in by Ryan J Ollos, 6 years ago

Fix indentation

File size: 5.8 KB
Line 
1"""
2email2trac:
3a pluggable email handler plugin for Trac
4http://trac.edgewall.org
5"""
6
7import email
8import email.Utils
9
10import os
11import sys, traceback
12import urllib
13import urllib2
14
15from datetime import datetime
16from interface import IEmailHandler
17from utils import reply_body
18from utils import reply_subject
19from utils import send_email
20from trac.core import *
21from trac.env import open_environment
22
23from trac.admin.api import IAdminCommandProvider #new command line
24from trac.perm import IPermissionRequestor # new trac permission
25
26
27
28debug = True
29
30
31
32# exception classes
33class EmailException(Exception):
34    """error exception when processing email messages"""
35
36class AddressLookupException(Exception):
37    """exception when try to match the email address for a project"""
38
39
40
41### command line handler
42
43class Email2Trac(Component) :
44
45
46    implements(IAdminCommandProvider, IPermissionRequestor)
47
48
49    def main(self, file) :
50        # read the message
51        f = open(file, 'r')
52        message = f.read()
53        try:
54            self.mail2project(message)  # process the message
55        except Exception, e:
56            raise
57
58
59
60
61    # IAdminCommandProvider methode
62    def get_admin_commands(self) :
63        yield ('email2Trac', '', 'use a mail saved in file to create or update ticket', None, self.main)
64
65
66
67    # Ipermissionrequestor methode
68    def get_permission_actions(self) :
69        ticketPerm = ['MAIL2TICKET_COMMENT', 'MAIL2TICKET_PROPERTIES', 'MAIL2TICKET_CREATE']
70        return ticketPerm + [('MAIL2TICKET_ADMIN', ticketPerm)]
71
72
73    ### methods for email processing
74
75    def lookup(self, message) :
76        """
77        matches a message with the environment and returns the message;
78        on lookup error, raises AddressLookupException
79        """
80        message = email.message_from_string(message)
81
82        # if the message is not to this project, ignore it
83        trac_address = self.env.config.get('mail', 'address')
84        if not trac_address:
85            trac_address = self.env.config.get('notification', 'smtp_replyto')
86        if not self.env.config.getbool('mail', 'accept_all') :
87            to = list(email.Utils.parseaddr(message['to']))
88            cc = message.get('cc','').strip()
89            if cc:
90                cc = [email.Utils.parseaddr(i.strip())[1]
91                      for i in cc.split(',') if i.strip()]
92                to = to + cc
93            delivered_to = message.get('delivered-to', '').strip()
94            if delivered_to:
95                to.append(email.Utils.parseaddr(delivered_to)[1])
96            original_to = message.get('x-original-to', '').strip()
97            if original_to:
98                to.append(original_to)
99
100            if trac_address not in to:
101                raise AddressLookupException("Email (to : %s ) does not match Trac address: %s" %(str(to),  trac_address))
102
103        return message
104
105    def mail2project(self, message) :
106        """relays an email message to a project"""
107
108        # keep copy of original message for error handling
109        original_message = email.message_from_string(message)
110
111        #keep trac email :
112        trac_mail = self.env.config.get('notification', 'smtp_replyto')
113
114        # whether or not to email back on error
115        email_errors = self.env.config.getbool('mail', 'email_errors', True)
116
117        # lookup the message
118        message = self.lookup(message)
119        # get the handlers
120        handlers = ExtensionPoint(IEmailHandler).extensions(self.env)
121        _handlers = self.env.config.getlist('mail', 'handlers')
122        if not _handlers: # default value
123            _handlers = [ 'RemoveQuotes', 'ReplyToTicket', 'EmailToTicket' ]
124        handler_dict = dict([(h.__class__.__name__, h)
125                                 for h in handlers])
126        handlers = [handler_dict[h] for h in _handlers
127                    if h in handler_dict ]
128        # handle the message
129        warnings = []
130        #is this email treated ?
131        email_treated = False
132        for handler in handlers:
133            if not handler.match(message) :
134                continue
135            try:
136                email_treated = True
137
138                message = handler.invoke(message, warnings)
139            except Exception, e:
140                # handle the error
141                print "Exception in user code:"
142                print '-'*60
143                traceback.print_exc(file=sys.stdout)
144                print '-'*60
145                raise
146            except EmailException, e:
147                if email_errors and original_message['from']:
148                    subject = reply_subject(original_message['subject'])
149                    response = 'Subject: %s\n\n%s' % (subject, reply_body(str(e), original_message))
150                    send_email(self.env,
151                               trac_mail,
152                               [ original_message['from'] ],
153                               response
154                               )
155                    warnings = [] # clear warnings
156                    return
157                else:
158                    raise
159
160            # if the message is consumed, quit processing
161            if not message:
162                break
163
164        if not email_treated :
165            warnings.append("Your email was not treated. It match none of the condition to be treated")
166        # email warnings
167        if warnings:
168
169            # format warning message
170            if len(warnings) == 1:
171                body = warnings[0]
172                pass
173            else:
174                body = "\n\n".join(["* %s" % warning.strip()
175                                    for warning in warnings])
176
177            # notify the sender
178            subject = reply_subject(original_message['subject'])
179            response = 'Subject: %s\n\n%s' % (subject, reply_body(body, original_message))
180            send_email(self.env,
181                       trac_mail,
182                       [ original_message['from'] ],
183                       response
184                       )
Note: See TracBrowser for help on using the repository browser.