##// END OF EJS Templates
control mailer debug with the .ini file
marcink -
r1169:f6dca275 beta
parent child Browse files
Show More
@@ -1,409 +1,410 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.lib.celerylib.tasks
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 RhodeCode task modules, containing all task that suppose to be run
7 7 by celery daemon
8 8
9 9 :created_on: Oct 6, 2010
10 10 :author: marcink
11 11 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
12 12 :license: GPLv3, see COPYING for more details.
13 13 """
14 14 # This program is free software; you can redistribute it and/or
15 15 # modify it under the terms of the GNU General Public License
16 16 # as published by the Free Software Foundation; version 2
17 17 # of the License or (at your opinion) any later version of the license.
18 18 #
19 19 # This program is distributed in the hope that it will be useful,
20 20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 22 # GNU General Public License for more details.
23 23 #
24 24 # You should have received a copy of the GNU General Public License
25 25 # along with this program; if not, write to the Free Software
26 26 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
27 27 # MA 02110-1301, USA.
28 28 from celery.decorators import task
29 29
30 30 import os
31 31 import traceback
32 32 import logging
33 33
34 34 from time import mktime
35 35 from operator import itemgetter
36 36
37 37 from pylons import config
38 38 from pylons.i18n.translation import _
39 39
40 40 from rhodecode.lib.celerylib import run_task, locked_task, str2bool
41 41 from rhodecode.lib.helpers import person
42 42 from rhodecode.lib.smtp_mailer import SmtpMailer
43 43 from rhodecode.lib.utils import OrderedDict, add_cache
44 44 from rhodecode.model import init_model
45 45 from rhodecode.model import meta
46 46 from rhodecode.model.db import RhodeCodeUi
47 47
48 48 from vcs.backends import get_repo
49 49
50 50 from sqlalchemy import engine_from_config
51 51
52 52 add_cache(config)
53 53
54 54 try:
55 55 import json
56 56 except ImportError:
57 57 #python 2.5 compatibility
58 58 import simplejson as json
59 59
60 60 __all__ = ['whoosh_index', 'get_commits_stats',
61 61 'reset_user_password', 'send_email']
62 62
63 63 CELERY_ON = str2bool(config['app_conf'].get('use_celery'))
64 64
65 65 def get_session():
66 66 if CELERY_ON:
67 67 engine = engine_from_config(config, 'sqlalchemy.db1.')
68 68 init_model(engine)
69 69 sa = meta.Session()
70 70 return sa
71 71
72 72 def get_repos_path():
73 73 sa = get_session()
74 74 q = sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
75 75 return q.ui_value
76 76
77 77 @task(ignore_result=True)
78 78 @locked_task
79 79 def whoosh_index(repo_location, full_index):
80 80 #log = whoosh_index.get_logger()
81 81 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
82 82 index_location = config['index_dir']
83 83 WhooshIndexingDaemon(index_location=index_location,
84 84 repo_location=repo_location, sa=get_session())\
85 85 .run(full_index=full_index)
86 86
87 87 @task(ignore_result=True)
88 88 @locked_task
89 89 def get_commits_stats(repo_name, ts_min_y, ts_max_y):
90 90 try:
91 91 log = get_commits_stats.get_logger()
92 92 except:
93 93 log = logging.getLogger(__name__)
94 94
95 95 from rhodecode.model.db import Statistics, Repository
96 96
97 97 #for js data compatibilty
98 98 author_key_cleaner = lambda k: person(k).replace('"', "")
99 99
100 100 commits_by_day_author_aggregate = {}
101 101 commits_by_day_aggregate = {}
102 102 repos_path = get_repos_path()
103 103 p = os.path.join(repos_path, repo_name)
104 104 repo = get_repo(p)
105 105
106 106 skip_date_limit = True
107 107 parse_limit = int(config['app_conf'].get('commit_parse_limit'))
108 108 last_rev = 0
109 109 last_cs = None
110 110 timegetter = itemgetter('time')
111 111
112 112 sa = get_session()
113 113
114 114 dbrepo = sa.query(Repository)\
115 115 .filter(Repository.repo_name == repo_name).scalar()
116 116 cur_stats = sa.query(Statistics)\
117 117 .filter(Statistics.repository == dbrepo).scalar()
118 118
119 119 if cur_stats is not None:
120 120 last_rev = cur_stats.stat_on_revision
121 121
122 122 #return if repo is empty
123 123 if not repo.revisions:
124 124 return True
125 125
126 126 if last_rev == repo.get_changeset().revision and len(repo.revisions) > 1:
127 127 #pass silently without any work if we're not on first revision or
128 128 #current state of parsing revision(from db marker) is the last revision
129 129 return True
130 130
131 131 if cur_stats:
132 132 commits_by_day_aggregate = OrderedDict(
133 133 json.loads(
134 134 cur_stats.commit_activity_combined))
135 135 commits_by_day_author_aggregate = json.loads(cur_stats.commit_activity)
136 136
137 137 log.debug('starting parsing %s', parse_limit)
138 138 lmktime = mktime
139 139
140 140 last_rev = last_rev + 1 if last_rev > 0 else last_rev
141 141
142 142 for cs in repo[last_rev:last_rev + parse_limit]:
143 143 last_cs = cs #remember last parsed changeset
144 144 k = lmktime([cs.date.timetuple()[0], cs.date.timetuple()[1],
145 145 cs.date.timetuple()[2], 0, 0, 0, 0, 0, 0])
146 146
147 147 if commits_by_day_author_aggregate.has_key(author_key_cleaner(cs.author)):
148 148 try:
149 149 l = [timegetter(x) for x in commits_by_day_author_aggregate\
150 150 [author_key_cleaner(cs.author)]['data']]
151 151 time_pos = l.index(k)
152 152 except ValueError:
153 153 time_pos = False
154 154
155 155 if time_pos >= 0 and time_pos is not False:
156 156
157 157 datadict = commits_by_day_author_aggregate\
158 158 [author_key_cleaner(cs.author)]['data'][time_pos]
159 159
160 160 datadict["commits"] += 1
161 161 datadict["added"] += len(cs.added)
162 162 datadict["changed"] += len(cs.changed)
163 163 datadict["removed"] += len(cs.removed)
164 164
165 165 else:
166 166 if k >= ts_min_y and k <= ts_max_y or skip_date_limit:
167 167
168 168 datadict = {"time":k,
169 169 "commits":1,
170 170 "added":len(cs.added),
171 171 "changed":len(cs.changed),
172 172 "removed":len(cs.removed),
173 173 }
174 174 commits_by_day_author_aggregate\
175 175 [author_key_cleaner(cs.author)]['data'].append(datadict)
176 176
177 177 else:
178 178 if k >= ts_min_y and k <= ts_max_y or skip_date_limit:
179 179 commits_by_day_author_aggregate[author_key_cleaner(cs.author)] = {
180 180 "label":author_key_cleaner(cs.author),
181 181 "data":[{"time":k,
182 182 "commits":1,
183 183 "added":len(cs.added),
184 184 "changed":len(cs.changed),
185 185 "removed":len(cs.removed),
186 186 }],
187 187 "schema":["commits"],
188 188 }
189 189
190 190 #gather all data by day
191 191 if commits_by_day_aggregate.has_key(k):
192 192 commits_by_day_aggregate[k] += 1
193 193 else:
194 194 commits_by_day_aggregate[k] = 1
195 195
196 196 overview_data = sorted(commits_by_day_aggregate.items(), key=itemgetter(0))
197 197 if not commits_by_day_author_aggregate:
198 198 commits_by_day_author_aggregate[author_key_cleaner(repo.contact)] = {
199 199 "label":author_key_cleaner(repo.contact),
200 200 "data":[0, 1],
201 201 "schema":["commits"],
202 202 }
203 203
204 204 stats = cur_stats if cur_stats else Statistics()
205 205 stats.commit_activity = json.dumps(commits_by_day_author_aggregate)
206 206 stats.commit_activity_combined = json.dumps(overview_data)
207 207
208 208 log.debug('last revison %s', last_rev)
209 209 leftovers = len(repo.revisions[last_rev:])
210 210 log.debug('revisions to parse %s', leftovers)
211 211
212 212 if last_rev == 0 or leftovers < parse_limit:
213 213 log.debug('getting code trending stats')
214 214 stats.languages = json.dumps(__get_codes_stats(repo_name))
215 215
216 216 try:
217 217 stats.repository = dbrepo
218 218 stats.stat_on_revision = last_cs.revision if last_cs else 0
219 219 sa.add(stats)
220 220 sa.commit()
221 221 except:
222 222 log.error(traceback.format_exc())
223 223 sa.rollback()
224 224 return False
225 225 if len(repo.revisions) > 1:
226 226 run_task(get_commits_stats, repo_name, ts_min_y, ts_max_y)
227 227
228 228 return True
229 229
230 230 @task(ignore_result=True)
231 231 def reset_user_password(user_email):
232 232 try:
233 233 log = reset_user_password.get_logger()
234 234 except:
235 235 log = logging.getLogger(__name__)
236 236
237 237 from rhodecode.lib import auth
238 238 from rhodecode.model.db import User
239 239
240 240 try:
241 241 try:
242 242 sa = get_session()
243 243 user = sa.query(User).filter(User.email == user_email).scalar()
244 244 new_passwd = auth.PasswordGenerator().gen_password(8,
245 245 auth.PasswordGenerator.ALPHABETS_BIG_SMALL)
246 246 if user:
247 247 user.password = auth.get_crypt_password(new_passwd)
248 248 user.api_key = auth.generate_api_key(user.username)
249 249 sa.add(user)
250 250 sa.commit()
251 251 log.info('change password for %s', user_email)
252 252 if new_passwd is None:
253 253 raise Exception('unable to generate new password')
254 254
255 255 except:
256 256 log.error(traceback.format_exc())
257 257 sa.rollback()
258 258
259 259 run_task(send_email, user_email,
260 260 "Your new rhodecode password",
261 261 'Your new rhodecode password:%s' % (new_passwd))
262 262 log.info('send new password mail to %s', user_email)
263 263
264 264
265 265 except:
266 266 log.error('Failed to update user password')
267 267 log.error(traceback.format_exc())
268 268
269 269 return True
270 270
271 271 @task(ignore_result=True)
272 272 def send_email(recipients, subject, body):
273 273 """
274 274 Sends an email with defined parameters from the .ini files.
275 275
276 276
277 277 :param recipients: list of recipients, it this is empty the defined email
278 278 address from field 'email_to' is used instead
279 279 :param subject: subject of the mail
280 280 :param body: body of the mail
281 281 """
282 282 try:
283 283 log = send_email.get_logger()
284 284 except:
285 285 log = logging.getLogger(__name__)
286 286
287 287 email_config = config
288 288
289 289 if not recipients:
290 290 recipients = [email_config.get('email_to')]
291 291
292 292 mail_from = email_config.get('app_email_from')
293 293 user = email_config.get('smtp_username')
294 294 passwd = email_config.get('smtp_password')
295 295 mail_server = email_config.get('smtp_server')
296 296 mail_port = email_config.get('smtp_port')
297 297 tls = str2bool(email_config.get('smtp_use_tls'))
298 298 ssl = str2bool(email_config.get('smtp_use_ssl'))
299 debug = str2bool(config.get('debug'))
299 300
300 301 try:
301 302 m = SmtpMailer(mail_from, user, passwd, mail_server,
302 mail_port, ssl, tls)
303 mail_port, ssl, tls, debug=debug)
303 304 m.send(recipients, subject, body)
304 305 except:
305 306 log.error('Mail sending failed')
306 307 log.error(traceback.format_exc())
307 308 return False
308 309 return True
309 310
310 311 @task(ignore_result=True)
311 312 def create_repo_fork(form_data, cur_user):
312 313 try:
313 314 log = create_repo_fork.get_logger()
314 315 except:
315 316 log = logging.getLogger(__name__)
316 317
317 318 from rhodecode.model.repo import RepoModel
318 319 from vcs import get_backend
319 320
320 321 repo_model = RepoModel(get_session())
321 322 repo_model.create(form_data, cur_user, just_db=True, fork=True)
322 323 repo_name = form_data['repo_name']
323 324 repos_path = get_repos_path()
324 325 repo_path = os.path.join(repos_path, repo_name)
325 326 repo_fork_path = os.path.join(repos_path, form_data['fork_name'])
326 327 alias = form_data['repo_type']
327 328
328 329 log.info('creating repo fork %s as %s', repo_name, repo_path)
329 330 backend = get_backend(alias)
330 331 backend(str(repo_fork_path), create=True, src_url=str(repo_path))
331 332
332 333 def __get_codes_stats(repo_name):
333 334 LANGUAGES_EXTENSIONS_MAP = {'scm': 'Scheme', 'asmx': 'VbNetAspx', 'Rout':
334 335 'RConsole', 'rest': 'Rst', 'abap': 'ABAP', 'go': 'Go', 'phtml': 'HtmlPhp',
335 336 'ns2': 'Newspeak', 'xml': 'EvoqueXml', 'sh-session': 'BashSession', 'ads':
336 337 'Ada', 'clj': 'Clojure', 'll': 'Llvm', 'ebuild': 'Bash', 'adb': 'Ada',
337 338 'ada': 'Ada', 'c++-objdump': 'CppObjdump', 'aspx':
338 339 'VbNetAspx', 'ksh': 'Bash', 'coffee': 'CoffeeScript', 'vert': 'GLShader',
339 340 'Makefile.*': 'Makefile', 'di': 'D', 'dpatch': 'DarcsPatch', 'rake':
340 341 'Ruby', 'moo': 'MOOCode', 'erl-sh': 'ErlangShell', 'geo': 'GLShader',
341 342 'pov': 'Povray', 'bas': 'VbNet', 'bat': 'Batch', 'd': 'D', 'lisp':
342 343 'CommonLisp', 'h': 'C', 'rbx': 'Ruby', 'tcl': 'Tcl', 'c++': 'Cpp', 'md':
343 344 'MiniD', '.vimrc': 'Vim', 'xsd': 'Xml', 'ml': 'Ocaml', 'el': 'CommonLisp',
344 345 'befunge': 'Befunge', 'xsl': 'Xslt', 'pyx': 'Cython', 'cfm':
345 346 'ColdfusionHtml', 'evoque': 'Evoque', 'cfg': 'Ini', 'htm': 'Html',
346 347 'Makefile': 'Makefile', 'cfc': 'ColdfusionHtml', 'tex': 'Tex', 'cs':
347 348 'CSharp', 'mxml': 'Mxml', 'patch': 'Diff', 'apache.conf': 'ApacheConf',
348 349 'scala': 'Scala', 'applescript': 'AppleScript', 'GNUmakefile': 'Makefile',
349 350 'c-objdump': 'CObjdump', 'lua': 'Lua', 'apache2.conf': 'ApacheConf', 'rb':
350 351 'Ruby', 'gemspec': 'Ruby', 'rl': 'RagelObjectiveC', 'vala': 'Vala', 'tmpl':
351 352 'Cheetah', 'bf': 'Brainfuck', 'plt': 'Gnuplot', 'G': 'AntlrRuby', 'xslt':
352 353 'Xslt', 'flxh': 'Felix', 'asax': 'VbNetAspx', 'Rakefile': 'Ruby', 'S': 'S',
353 354 'wsdl': 'Xml', 'js': 'Javascript', 'autodelegate': 'Myghty', 'properties':
354 355 'Ini', 'bash': 'Bash', 'c': 'C', 'g': 'AntlrRuby', 'r3': 'Rebol', 's':
355 356 'Gas', 'ashx': 'VbNetAspx', 'cxx': 'Cpp', 'boo': 'Boo', 'prolog': 'Prolog',
356 357 'sqlite3-console': 'SqliteConsole', 'cl': 'CommonLisp', 'cc': 'Cpp', 'pot':
357 358 'Gettext', 'vim': 'Vim', 'pxi': 'Cython', 'yaml': 'Yaml', 'SConstruct':
358 359 'Python', 'diff': 'Diff', 'txt': 'Text', 'cw': 'Redcode', 'pxd': 'Cython',
359 360 'plot': 'Gnuplot', 'java': 'Java', 'hrl': 'Erlang', 'py': 'Python',
360 361 'makefile': 'Makefile', 'squid.conf': 'SquidConf', 'asm': 'Nasm', 'toc':
361 362 'Tex', 'kid': 'Genshi', 'rhtml': 'Rhtml', 'po': 'Gettext', 'pl': 'Prolog',
362 363 'pm': 'Perl', 'hx': 'Haxe', 'ascx': 'VbNetAspx', 'ooc': 'Ooc', 'asy':
363 364 'Asymptote', 'hs': 'Haskell', 'SConscript': 'Python', 'pytb':
364 365 'PythonTraceback', 'myt': 'Myghty', 'hh': 'Cpp', 'R': 'S', 'aux': 'Tex',
365 366 'rst': 'Rst', 'cpp-objdump': 'CppObjdump', 'lgt': 'Logtalk', 'rss': 'Xml',
366 367 'flx': 'Felix', 'b': 'Brainfuck', 'f': 'Fortran', 'rbw': 'Ruby',
367 368 '.htaccess': 'ApacheConf', 'cxx-objdump': 'CppObjdump', 'j': 'ObjectiveJ',
368 369 'mll': 'Ocaml', 'yml': 'Yaml', 'mu': 'MuPAD', 'r': 'Rebol', 'ASM': 'Nasm',
369 370 'erl': 'Erlang', 'mly': 'Ocaml', 'mo': 'Modelica', 'def': 'Modula2', 'ini':
370 371 'Ini', 'control': 'DebianControl', 'vb': 'VbNet', 'vapi': 'Vala', 'pro':
371 372 'Prolog', 'spt': 'Cheetah', 'mli': 'Ocaml', 'as': 'ActionScript3', 'cmd':
372 373 'Batch', 'cpp': 'Cpp', 'io': 'Io', 'tac': 'Python', 'haml': 'Haml', 'rkt':
373 374 'Racket', 'st':'Smalltalk', 'inc': 'Povray', 'pas': 'Delphi', 'cmake':
374 375 'CMake', 'csh':'Tcsh', 'hpp': 'Cpp', 'feature': 'Gherkin', 'html': 'Html',
375 376 'php':'Php', 'php3':'Php', 'php4':'Php', 'php5':'Php', 'xhtml': 'Html',
376 377 'hxx': 'Cpp', 'eclass': 'Bash', 'css': 'Css',
377 378 'frag': 'GLShader', 'd-objdump': 'DObjdump', 'weechatlog': 'IrcLogs',
378 379 'tcsh': 'Tcsh', 'objdump': 'Objdump', 'pyw': 'Python', 'h++': 'Cpp',
379 380 'py3tb': 'Python3Traceback', 'jsp': 'Jsp', 'sql': 'Sql', 'mak': 'Makefile',
380 381 'php': 'Php', 'mao': 'Mako', 'man': 'Groff', 'dylan': 'Dylan', 'sass':
381 382 'Sass', 'cfml': 'ColdfusionHtml', 'darcspatch': 'DarcsPatch', 'tpl':
382 383 'Smarty', 'm': 'ObjectiveC', 'f90': 'Fortran', 'mod': 'Modula2', 'sh':
383 384 'Bash', 'lhs': 'LiterateHaskell', 'sources.list': 'SourcesList', 'axd':
384 385 'VbNetAspx', 'sc': 'Python'}
385 386
386 387 repos_path = get_repos_path()
387 388 p = os.path.join(repos_path, repo_name)
388 389 repo = get_repo(p)
389 390 tip = repo.get_changeset()
390 391 code_stats = {}
391 392
392 393 def aggregate(cs):
393 394 for f in cs[2]:
394 395 ext = f.extension
395 396 key = LANGUAGES_EXTENSIONS_MAP.get(ext, ext)
396 397 key = key or ext
397 398 if ext in LANGUAGES_EXTENSIONS_MAP.keys() and not f.is_binary:
398 399 if code_stats.has_key(key):
399 400 code_stats[key] += 1
400 401 else:
401 402 code_stats[key] = 1
402 403
403 404 map(aggregate, tip.walk('/'))
404 405
405 406 return code_stats or {}
406 407
407 408
408 409
409 410
@@ -1,143 +1,143 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.lib.smtp_mailer
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 Simple smtp mailer used in RhodeCode
7 7
8 8 :created_on: Sep 13, 2010
9 9 :copyright: (c) 2011 by marcink.
10 10 :license: LICENSE_NAME, see LICENSE_FILE for more details.
11 11 """
12 12
13 13 import logging
14 14 import smtplib
15 15 import mimetypes
16 16 from socket import sslerror
17 17
18 18 from email.mime.multipart import MIMEMultipart
19 19 from email.mime.image import MIMEImage
20 20 from email.mime.audio import MIMEAudio
21 21 from email.mime.base import MIMEBase
22 22 from email.mime.text import MIMEText
23 23 from email.utils import formatdate
24 24 from email import encoders
25 25
26 26 class SmtpMailer(object):
27 27 """SMTP mailer class
28 28
29 29 mailer = SmtpMailer(mail_from, user, passwd, mail_server, mail_port, ssl, tls)
30 30 mailer.send(recipients, subject, body, attachment_files)
31 31
32 32 :param recipients might be a list of string or single string
33 33 :param attachment_files is a dict of {filename:location}
34 34 it tries to guess the mimetype and attach the file
35 35
36 36 """
37 37
38 38 def __init__(self, mail_from, user, passwd, mail_server,
39 mail_port=None, ssl=False, tls=False):
39 mail_port=None, ssl=False, tls=False, debug=False):
40 40
41 41 self.mail_from = mail_from
42 42 self.mail_server = mail_server
43 43 self.mail_port = mail_port
44 44 self.user = user
45 45 self.passwd = passwd
46 46 self.ssl = ssl
47 47 self.tls = tls
48 self.debug = False
48 self.debug = debug
49 49
50 50 def send(self, recipients=[], subject='', body='', attachment_files=None):
51 51
52 52 if isinstance(recipients, basestring):
53 53 recipients = [recipients]
54 54 if self.ssl:
55 55 smtp_serv = smtplib.SMTP_SSL(self.mail_server, self.mail_port)
56 56 else:
57 57 smtp_serv = smtplib.SMTP(self.mail_server, self.mail_port)
58 58
59 59 if self.tls:
60 60 smtp_serv.ehlo()
61 61 smtp_serv.starttls()
62 62
63 63 if self.debug:
64 64 smtp_serv.set_debuglevel(1)
65 65
66 66 smtp_serv.ehlo()
67 67
68 68 #if server requires authorization you must provide login and password
69 69 #but only if we have them
70 70 if self.user and self.passwd:
71 71 smtp_serv.login(self.user, self.passwd)
72 72
73 73
74 74 date_ = formatdate(localtime=True)
75 75 msg = MIMEMultipart()
76 76 msg['From'] = self.mail_from
77 77 msg['To'] = ','.join(recipients)
78 78 msg['Date'] = date_
79 79 msg['Subject'] = subject
80 80 msg.preamble = 'You will not see this in a MIME-aware mail reader.\n'
81 81
82 82 msg.attach(MIMEText(body))
83 83
84 84 if attachment_files:
85 85 self.__atach_files(msg, attachment_files)
86 86
87 87 smtp_serv.sendmail(self.mail_from, recipients, msg.as_string())
88 88 logging.info('MAIL SEND TO: %s' % recipients)
89 89
90 90 try:
91 91 smtp_serv.quit()
92 92 except sslerror:
93 93 # sslerror is raised in tls connections on closing sometimes
94 94 pass
95 95
96 96
97 97
98 98 def __atach_files(self, msg, attachment_files):
99 99 if isinstance(attachment_files, dict):
100 100 for f_name, msg_file in attachment_files.items():
101 101 ctype, encoding = mimetypes.guess_type(f_name)
102 102 logging.info("guessing file %s type based on %s" , ctype, f_name)
103 103 if ctype is None or encoding is not None:
104 104 # No guess could be made, or the file is encoded (compressed), so
105 105 # use a generic bag-of-bits type.
106 106 ctype = 'application/octet-stream'
107 107 maintype, subtype = ctype.split('/', 1)
108 108 if maintype == 'text':
109 109 # Note: we should handle calculating the charset
110 110 file_part = MIMEText(self.get_content(msg_file),
111 111 _subtype=subtype)
112 112 elif maintype == 'image':
113 113 file_part = MIMEImage(self.get_content(msg_file),
114 114 _subtype=subtype)
115 115 elif maintype == 'audio':
116 116 file_part = MIMEAudio(self.get_content(msg_file),
117 117 _subtype=subtype)
118 118 else:
119 119 file_part = MIMEBase(maintype, subtype)
120 120 file_part.set_payload(self.get_content(msg_file))
121 121 # Encode the payload using Base64
122 122 encoders.encode_base64(msg)
123 123 # Set the filename parameter
124 124 file_part.add_header('Content-Disposition', 'attachment',
125 125 filename=f_name)
126 126 file_part.add_header('Content-Type', ctype, name=f_name)
127 127 msg.attach(file_part)
128 128 else:
129 129 raise Exception('Attachment files should be'
130 130 'a dict in format {"filename":"filepath"}')
131 131
132 132 def get_content(self, msg_file):
133 133 """Get content based on type, if content is a string do open first
134 134 else just read because it's a probably open file object
135 135
136 136 :param msg_file:
137 137 """
138 138 if isinstance(msg_file, str):
139 139 return open(msg_file, "rb").read()
140 140 else:
141 141 #just for safe seek to 0
142 142 msg_file.seek(0)
143 143 return msg_file.read()
General Comments 0
You need to be logged in to leave comments. Login now