Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# -*- coding: utf-8 -*-
2"""
3@file
4@brief Functions to dump emails
5"""
6import os
7import datetime
8import json
9from jinja2 import Template
10from pyquickhelper.loghelper import noLOG
11from ..helpers import iterator_prev_next
12from .renderer import Renderer
13from .email_message_style import template_email_list_html_iter, template_email_list_html_begin
14from .email_message_style import template_email_list_html_end, template_email_css
17class EmailMessageListRenderer(Renderer):
18 """
19 Defines a way to render a list of emails with a template
20 template based on `Jinja2 <http://jinja.pocoo.org/docs/dev/>`_.
22 .. exref::
23 :title: Render a list of emails
25 The following example extracts all mails in a folder of a gmail inbox,
26 dumps them in a folder and produces a summary which connects to them.
28 ::
30 from pymmails import EmailMessageRenderer, EmailMessageListRenderer, MailBoxImap
31 box = MailBoxImap(user, pwd, server)
32 box.login()
33 mails = box.enumerate_mails_in_folder("<your_folder)")
35 email_render = EmailMessageRenderer()
37 render = EmailMessageListRenderer(title="list of mails", email_renderer=email_render)
38 render.write(iter=mails, location=temp, filename="summary.html")
39 box.logout())
40 render.flush()
41 """
43 def __init__(self, title, email_renderer, tmpl_begin=None, tmpl_iter=None, tmpl_end=None,
44 css=None, style_table="dataframe100l", style_highlight="dataframe100l_hl",
45 buffer_write=None, fLOG=noLOG):
46 """
47 @param title title
48 @param email_renderer email renderer (see @see cl EmailMessageRenderer)
49 @param tmpl_begin template which begins the summary
50 @param tmpl_iter template which adds an element
51 @param tmpl_end template which ends the summary
52 @param css template style
53 @param style_table style for the table
54 @param style_highlight style for highlighted cells
55 @param buffer_write instance of class @see cl BufferFilesWriting
56 @param fLOG logging function
57 """
58 if tmpl_begin is None:
59 _template_begin = template_email_list_html_begin
60 elif len(tmpl_begin) < 5000 and os.path.exists(tmpl_begin):
61 with open(tmpl_begin, "r", encoding="utf8") as f:
62 _template_begin = f.read()
63 else:
64 _template_begin = tmpl_begin
66 if tmpl_iter is None:
67 _template_iter = template_email_list_html_iter
68 elif len(tmpl_iter) < 5000 and os.path.exists(tmpl_iter):
69 with open(tmpl_iter, "r", encoding="utf8") as f:
70 _template_iter = f.read()
71 else:
72 _template_iter = tmpl_iter
74 if tmpl_end is None:
75 _template_end = template_email_list_html_end
76 elif len(tmpl_end) < 5000 and os.path.exists(tmpl_end):
77 with open(tmpl_end, "r", encoding="utf8") as f:
78 _template_end = f.read()
79 else:
80 _template_end = tmpl_end
82 if css is None:
83 _css = template_email_css
84 elif len(css) < 5000 and os.path.exists(css):
85 with open(css, "r", encoding="utf8") as f:
86 _css = f.read()
87 else:
88 _css = css
90 if buffer_write is None:
91 buffer_write = email_renderer.BufferWrite
93 Renderer.__init__(self, tmpl=_template_iter, css=_css, style_table=style_table,
94 style_highlight=style_highlight, buffer_write=buffer_write, fLOG=fLOG)
96 self._email_renderer = email_renderer
97 self._template_begin = Template(_template_begin)
98 self._template_end = Template(_template_end)
99 self._title = title
101 def render(self, location, iter, attachments=None, # pylint: disable=W0237
102 file_css="mail_style.css"):
103 """
104 Renders a mail.
106 @paramp location location where this mail should be saved
107 @param iter iterator on tuple (object, function to call to render the object)
108 @param attachments used to produce a JSON list
109 @param file_css css file (where it is supposed to be stored)
110 @return html, css (content), attachements as JSON
112 The method populate fields ``now``, ``message``, ``css``, ``render``, ``location``, ``title``.
113 """
114 now = datetime.datetime.now()
115 file_css = os.path.relpath(file_css, location)
116 content = []
117 self.fLOG("[EmailMessageListRenderer.render] begin")
118 css = self._css.render()
119 h = self._template_begin.render(css=file_css, render=self,
120 location=location, title=self._title, now=now)
121 content.append(h)
122 self.fLOG("[EmailMessageListRenderer.render] iterate")
124 def iter_on_mail():
125 "local function"
126 for i, mail3 in enumerate(iterator_prev_next(sorted(iter))):
127 prev, item, next = mail3
128 if i % 10 == 9:
129 self.fLOG(
130 "[EmailMessageListRenderer.render] iterate", i + 1)
131 if not isinstance(item, tuple):
132 raise TypeError(
133 "expects a tuple (EmailMessage, function to render) not {0}".format(type(item)))
134 prev_mail = prev[0].default_filename() + \
135 ".html" if prev else None
136 next_mail = next[0].default_filename() + \
137 ".html" if next else None
138 obj, f = item
139 f(obj, location, prev_mail, next_mail)
140 yield prev[0] if prev else None, item[0], next[0] if next else None
142 for _, item, __ in iter_on_mail():
143 h = self._template.render(message=item, css=file_css, render=self, location=location,
144 title=self._title, url=item.default_filename() + ".html", now=now)
145 content.append(h)
147 self.fLOG("[EmailMessageListRenderer.render] end")
148 h = self._template_end.render(css=file_css, render=self,
149 location=location, title=self._title, now=now)
150 json_attachments = []
151 if attachments is not None:
152 for att in attachments:
153 satt = att.replace("\\", "/")
154 json_attachments.append(dict(a=satt, name=satt))
155 content.append(h)
156 return "\n".join(content), css, json_attachments
158 def write(self, location, iter, filename, attachments=None, # pylint: disable=W0221
159 overwrite=False, file_css="mail_style.css",
160 file_jsatt="_summaryattachements.json", encoding="utf8",
161 attach_folder="attachments"):
162 """
163 Writes a list of mails in a folder and writes a summary.
165 @param location location
166 @param mail instance of @see cl EmailMessage
167 @param attachments list of attachments (see @see me dump_attachments)
168 @param overwrite the function does not overwrite
169 @param file_css css file (where it is supposed to be stored)
170 @param file_jsatt list of attachments in json format
171 ``[{'a': 'href', 'name': 'anchor', ...}, ...]``
172 @param encoding encoding
173 @param attach_folder attachments folder
174 @return list of written local files
176 The method calls method :meth:`flush
177 <pymmails.helpers.buffer_files_writing.BufferFilesWriting.flush>`.
178 """
179 if not hasattr(iter, '__iter__'):
180 raise TypeError("class {0} is not iterable".format(type(iter)))
182 full_css = os.path.join(location, file_css)
183 full_mail = os.path.join(location, filename)
184 full_file_jsatt = os.path.join(location, file_jsatt)
185 if self.BufferWrite.exists(full_css, local=not overwrite) and \
186 self.BufferWrite.exists(full_mail, local=not overwrite):
187 self.fLOG("[EmailMessageListRenderer.write] already exist css='{0}' html='{1}']".format(
188 full_css, full_mail))
189 return [full_mail, full_css]
191 def fwrite(message, location, prev_mail, next_mail):
192 "local function"
193 res = message.dump(self._email_renderer, location=location,
194 prev_mail=prev_mail, next_mail=next_mail, fLOG=self.fLOG,
195 overwrite=overwrite, attach_folder=attach_folder)
196 html, css = res[0]
197 atts = res[1]
198 return html, css, atts
200 def walk_iter():
201 "local function"
202 for obj in iter:
203 yield obj, fwrite
205 html, css, json_att = self.render(
206 location, walk_iter(), file_css=full_css)
207 wrote = []
208 if not self.BufferWrite.exists(full_css, local=not overwrite):
209 f = self.BufferWrite.open(full_css, text=True, encoding=encoding)
210 f.write(css)
211 wrote.append(full_css)
212 if not self.BufferWrite.exists(full_mail, local=not overwrite):
213 f = self.BufferWrite.open(full_mail, text=True, encoding=encoding)
214 f.write(html)
215 wrote.append(full_mail)
216 if json_att and not self.BufferWrite.exists(full_file_jsatt, local=not overwrite):
217 f = self.BufferWrite.open(
218 full_file_jsatt, text=True, encoding=encoding)
219 js = json.dumps(json_att)
220 f.write(js)
221 wrote.append(full_file_jsatt)
222 return wrote