This repository has been archived by the owner on Mar 16, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 27
/
Copy pathmaildir2ical.py
executable file
·226 lines (180 loc) · 6.56 KB
/
maildir2ical.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
#!/usr/bin/python
##############################################################################
#
# Copyright (C) 2007 Kevin Deldycke <[email protected]>
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
"""
Requirements:
* python
* python iCalendar
Features:
*
*
TODO:
*
*
*
"""
################### Start of user config ###################
# Maildir to browse
MAIL_DIR = "/home/kevin/Maildir"
# Name of the iCalendar file
ICAL_FILE = "kev-mails.ics"
# Number of minutes before the mail (= time when the iCal event will start)
TIME_SLOT = 5
# Do not include details like mail body and mail receiver. Just keep the author and the date.
CONFIDENTIAL = False
#################### End of user config ####################
################ Do not modify code below ! ################
import mailbox, email, random, sys
from os import getcwdu
from os.path import abspath, exists, isdir
from datetime import datetime, timedelta
from icalendar import Calendar, Event, UTC
# Global variable that contain the calendar and statistics
global cal, mail_count
def decodeHeader(h):
"""
Parse and decode header data (try to).
"""
parts = email.Header.decode_header(h)
try:
new_header = email.Header.make_header(parts)
except UnicodeDecodeError:
# Force UTF-8 header
for part_index in range(len(parts)):
(string, enc) = parts[part_index]
if enc == None:
parts[part_index] = (string, 'utf-8')
try:
new_header = email.Header.make_header(parts)
except:
return h
return unicode(new_header)
def browseMailDir(maildir):
"""
This recursive method browse each folder and convert each mail that match criterion to an event
"""
global mail_count
# Analyse each mail in the maildir
for maildir_mail in maildir:
# parse the message:
mail = email.message_from_string(str(maildir_mail))
# Reject all mails by default
reject = True
# Filter emails to find mails that came from me
author = decodeHeader(mail['From'])
if author.find("[email protected]") != -1:
# Mail come from me, keep it
reject = False
# Eliminate false-positive now.
# Ignore automatic unit tests mail reports sent by the dev server (aka 10.1.0.33)
# XXX Is a replied mail feature this IP adress ??
for v in (mail.get_all("Received") or []):
if decodeHeader(v).find("10.1.0.33") != -1:
reject = True
break
# Get a one-line subject
if not CONFIDENTIAL:
subject = decodeHeader(mail['Subject']).replace('\t', ' ').replace('\n', '')
else:
subject = "Mail"
# Proceed to next mail if email was not detected as mine
if reject:
#print " SKIP - %s -by- %s" % (subject, author)
continue
else:
print " KEEP - %s -by- %s" % (subject, author)
# Convert mail date to python datetime object
mail_date = email.Utils.parsedate(decodeHeader(mail['Date']))
py_datetime = datetime( mail_date[0]
, mail_date[1]
, mail_date[2]
, mail_date[3]
, mail_date[4]
, mail_date[5]
, 0
, tzinfo=UTC
)
# iCalendar events must be defined by a time slot with a start and a stop date/time.
# There is no such equivalent for mail: a mail has just a date.
# I choose to use the mail date as the end of the iCal event. The start of the event will be set as the mail date minus 5 minutes.
event_start = py_datetime - timedelta(minutes=TIME_SLOT)
# Get the destination email
if not CONFIDENTIAL:
dest = decodeHeader(mail['To'])
else:
dest = "XXXX XXXXXXXXX <[email protected]>"
# Get the body of the mail
mail_body = ""
if not CONFIDENTIAL:
for part in mail.walk():
if part.get_content_type() == "text/plain":
if part.get_content_charset() == None:
mail_body += unicode(part.get_payload(decode=True))
else:
mail_body += unicode(part.get_payload(decode=True), part.get_content_charset())
# Create a new calendar event
event = Event()
event.add('summary', subject)
event.add('description', "From: %s\nTo: %s\n\n%s" % (author, dest, mail_body))
event.add('dtstart', event_start)
event.add('dtend', py_datetime)
event.add('dtstamp', event_start)
event.add('priority', 5)
# Generate message UID
if mail.has_key("Message-Id"):
event['uid'] = decodeHeader(mail["Message-Id"])
else:
event['uid'] = '%s-%s-%[email protected]' % (py_datetime, author, random.random())
# Add the event to the calendar
cal.add_component(event)
# Compute statistics
mail_count += 1
# Browse each sub maildir
for folder in maildir.list_folders():
sub_maildir = maildir.get_folder(folder)
browseMailDir(sub_maildir)
if __name__ == "__main__":
# Use script folder as work folder and normalize path
work_dir = abspath(getcwdu())
ical_file = abspath("%s/%s" % (work_dir, ICAL_FILE))
maildir_path = abspath(MAIL_DIR)
# Check maildir
if not exists(maildir_path):
print "FATAL - '%s' maildir doesn't exist !" % maildir_path
sys.exit(1)
elif not isdir(maildir_path):
print "FATAL - '%s' maildir is not a directory !" % maildir_path
sys.exit(1)
# Init statistics variables
mail_count = 0
# Create a brand new calendar
cal = Calendar()
cal.add('prodid', '-//MAILDIR2ICAL//kev.coolcavemen.com//')
cal.add('version', '2.0')
# Open and parse the top maildir
maildir = mailbox.Maildir(MAIL_DIR, email.message_from_file)
browseMailDir(maildir)
# Write the iCal file
f = open(ical_file, "w")
f.write(cal.as_string())
f.close()
# Exit
print " INFO - Calendar created as '%s' with %s mails." % (ical_file, mail_count)
sys.exit(0)