Welcome, guest | Sign In | My Account | Store | Cart

This python script monitors the IMAP mail server for the given account and moves the mails with attachments to "Downloadedmails" folder in server after downloading the attachments to the individual directories on localmachine with the timestamp.

Python, 276 lines
  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
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
#------------------------------------------------------------------------------
#           Name: attdownload.py
#         Author: Suresh Kumar MP
#  Last Modified: 09/29/06
#    Description: This python script monitors the IMAP mail server for the given
#				  account and moves the mails with attachments to "Downloadedmails"
#				  folder in server after downloading the attachments to the individual
#				  directories on localmachine with a timestamp.
#------------------------------------------------------------------------------
import getopt, getpass, os, sys, time
import imaplib
import email, email.Errors, email.Header, email.Message, email.Utils
from time import strftime
from time import sleep


Usage = """Usage: %s  --user <user> --password <password> --frequency <polling frequency> <imap-server>

	--user		  Provide <user> for authentication on <imap-server>
			
	--password    Password for the given user

	--frequency	  Provide the mail server polling frequency in seconds	

	 Example:  attdownload.py --user username --password password --frequency 300 10.133.23.124

"""

AttachDir = '.'			# Attachment Directory Path
DeleteMessages = 0
SaveAttachments = 1		# Save all attachments found
User = None				# IMAP4 user
Password = None			# User password
Frequency = None		# Mail server polling frequency
exists = 0				
name = 0

def usage(reason=''):
	sys.stdout.flush()
	if reason: sys.stderr.write('\t%s\n\n' % reason)
	head, tail = os.path.split(sys.argv[0])
	sys.stderr.write(Usage % tail)
	sys.exit(1)

def args():
	try:
		optlist, args = getopt.getopt(sys.argv[1:], '?',['user=', 'password=', 'frequency='])
	except getopt.error, val:
		usage(val)

	global SaveAttachments
	global User
	global Password
	global Frequency
	
	for opt,val in optlist:
		if opt == '--user':
			User = val
		elif opt == '--password':
			Password = val
		elif opt == '--frequency':
			Frequency = float(val)
		else:
			usage()

	if len(args) != 1:
		usage()

	return args[0]

def write_file(filename, addr, data):
	os.chdir(addr)
	fd = open(filename, "wb")	
	fd.write(data)
	fd.close()
	

def gen_filename(name, mtyp, addr, date, n):

	timepart = strftime("%d %b %y %H_%M_%S")	
	file = email.Header.decode_header(name)[0][0]
	file = os.path.basename(file)
	print "Saved attachment  " + file + "  from  " + addr
	print "\n"
	path = os.path.join(AttachDir, file)
	pre, ext = os.path.splitext(file)
	pre = pre + "_" + timepart
	path = '%s%s' % (os.path.join(AttachDir, pre),  ext)
	return path

def error(reason):
	sys.stderr.write('%s\n' % reason)
	sys.exit(1)
	
def walk_parts(msg, addr, date, count, msgnum):
	for part in msg.walk():
		if part.is_multipart():
			continue
		dtypes = part.get_params(None, 'Content-Disposition')
		if not dtypes:
			if part.get_content_type() == 'text/plain':
				continue
			ctypes = part.get_params()
			if not ctypes:
				continue
			for key,val in ctypes:
				if key.lower() == 'name':
					filename = gen_filename(val, part.get_content_type(), addr, date, count)
					break
			else:
				continue
		else:
			attachment,filename = None,None
			for key,val in dtypes:
				key = key.lower()
				if key == 'filename':
					filename = val
				if key == 'attachment':
					attachment = 1
			if not attachment:
				continue
			filename = gen_filename(filename, part.get_content_type(), addr, date, count)
			
		try:
			data = part.get_payload(decode=1)
		except:
			typ, val = sys.exc_info()[:2]
			warn("Message %s attachment decode error: %s for %s ``%s''"
				% (msgnum, str(val), part.get_content_type(), filename))
			continue

		if not data:
			warn("Could not decode attachment %s for %s"
				% (part.get_content_type(), filename))
			continue

		if type(data) is type(msg):
			count = walk_parts(data, addr, date, count, msgnum)
			continue
		
		if SaveAttachments:
			exists = "0"
			try:
				curdir= os.getcwd()
				list = os.listdir('.\\')
				for name in list:
					if name == addr:
						exists = "1"
						break
				if exists == "1":
					write_file(filename, addr, data)
					os.chdir(curdir)					
				else:
					os.mkdir(addr)
					write_file(filename, addr, data)
					os.chdir(curdir)
					exists == "0"
					os.chdir(curdir)
			except IOError, val:
				error('Could not create "%s": %s' % (filename, str(val)))
	
		count += 1

	return count


def process_message(text, msgnum):
	
	try:
		msg = email.message_from_string(text)
	except email.Errors.MessageError, val:
		warn("Message %s parse error: %s" % (msgnum, str(val)))
		return text

	date = msg['Date'] or 'Thu, 18 Sep 2006 12:02:27 +1000'
	date = time.strftime('%Y_%m_%d.%T', email.Utils.parsedate(date))
	addr = email.Utils.parseaddr(msg['From'])[1]
	
	
	
	attachments_found = walk_parts(msg, addr, date, 0, msgnum)
	if attachments_found:
		return ''
	else:	
		return None


def read_messages(fd):

	data = []; app = data.append

	for line in fd:
		if line[:5] == 'From ' and data:
			yield ''.join(data)
			data[:] = []
		app(line)

	if data:
		yield ''.join(data)


def process_server(host):

	global DeleteAttachments

	try:
		mbox = imaplib.IMAP4(host)
	except:
		typ,val = sys.exc_info()[:2]
		error('Could not connect to IMAP server "%s": %s'
				% (host, str(val)))

	if User or mbox.state != 'AUTH':
		user = User or getpass.getuser()
	if Password == "":
		pasw = getpass.getpass("Please enter password for %s on %s: "
						% (user, host))
	else:
		pasw = Password
		
	try:
		typ,dat = mbox.login(user, pasw)
	except:
		typ,dat = sys.exc_info()[:2]

	if typ != 'OK':
		error('Could not open INBOX for "%s" on "%s": %s'
			% (user, host, str(dat)))

	mbox.select('Inbox')
	#mbox.select(readonly=(DeleteMessages))
	typ, dat = mbox.search(None, 'ALL')
	mbox.create("DownloadedMails")
	
	deleteme = []
	for num in dat[0].split():
		typ, dat = mbox.fetch(num, '(RFC822)')
		if typ != 'OK':
			error(dat[-1])
		message = dat[0][1]
		if process_message(message, num) == '':
			deleteme.append(num)
	if deleteme == []:
		print "\n"
		print "No mails with attachment found in INBOX"
		
		
	deleteme.sort()
	for number in deleteme:
		mbox.copy(number, 'DownloadedMails')
		mbox.store(number, "+FLAGS.SILENT", '(\\Deleted)')
		

	mbox.expunge()
	mbox.close()
	mbox.logout()

def main():

	file_or_server = args()
	print "\n"
	print "Monitoring the Mail server  " + file_or_server + "  for account  " + User
	while 1:
		process_server(file_or_server)
		printfre = str(Frequency)
		print "Sleeping for  " + printfre + "  seconds..."
		sleep(Frequency)
		
		


if __name__ == '__main__':
	try:
		main()
	except KeyboardInterrupt:
		pass

1 comment

Eric S 12 years, 8 months ago  # | flag

Suresh, Thanks for your script!

It fails on Unix-like systems though. Line 145 is windows specific:

list = os.listdir('.\\')

I’m not aware what path exactly you are trying to list? There should be a platform-agnostic way to achieve this.

Thanks for your reply,

Eric