Уведомления

Группа в Telegram: @pythonsu

#1 Март 31, 2014 16:53:08

kolin_k
Зарегистрирован: 2014-03-31
Сообщения: 6
Репутация: +  0  -
Профиль   Отправить e-mail  

Допиливание скрипта под определенную задачу. Imaplib.

На просторах интернета нашел такой скрипт:

#!/usr/bin/env python
 
import getpass, imaplib, email, os
from email import parser
 
detach_dir = '/home/samba/shares/unique'
M = imaplib.IMAP4('mail.ru')
M.login('test@mail.ru', 'password')
M.select()
typ, data = M.search(None, 'FROM', '"test@mail.ru"')
for num in data[0].split():
    typ, data = M.fetch(num, '(RFC822)')
    email_body = data[0][1] # getting the mail content
    mail = email.message_from_string(email_body) # parsing the mail content to get a mail object
    
    #Check if any attachments at all
    if mail.get_content_maintype() != 'multipart':
    continue
 
    print "["+mail["From"]+"] :" + mail["Subject"]
    
    # we use walk to create a generator so we can iterate on the parts and forget about the recursive headache
    for part in mail.walk():
        # multipart are just containers, so we skip them
    if part.get_content_maintype() == 'multipart':
        continue
    
        # is this part an attachment ?
        if part.get('Content-Disposition') is None: 
        continue
    
    filename = part.get_filename()
        counter = 1
        
        # if there is no filename, we create one with a counter to avoid duplicates
        if not filename:
            filename = 'part-%03d%s' % (counter, 'bin')
        counter += 1
    
    att_path = os.path.join(detach_dir, filename)
        
        #Check if its already there
        if not os.path.isfile(att_path) :
        # finally write the stuff
        fp = open(att_path, 'wb')
            fp.write(part.get_payload(decode=True))
            fp.close()
    
M.close()
M.logout()
Нужно добавить, чтобы аттачи складывались в папку с текущей датой и письмо удалялось после этого. И обрабатывались все письма, а не только от test@mail.ru

Последняя версия моих экспериментов (с учетом подсказок людей):
#!/usr/bin/env python
 
import getpass, imaplib, email, os
from email import parser
 
detach_dir = '/home/samba/shares/unique'
detach_new = '/home/samba/shares/unique/%s/' % datetime.date.today()   <-----------------
M = imaplib.IMAP4('mail.ru')
M.login('test@mail.ru', 'password')
M.select()
typ, data = M.search(None, 'ALL') <-----------------
if data != ['']:            <-----------------
    os.makedirs(detach_new)  <-----------------
for num in data[0].split():
    typ, data = M.fetch(num, '(RFC822)')
    email_body = data[0][1] # getting the mail content
    mail = email.message_from_string(email_body) # parsing the mail content to get a mail object
    
    #Check if any attachments at all
    if mail.get_content_maintype() != 'multipart':
    continue
 
    print "["+mail["From"]+"] :" + mail["Subject"]
    
    # we use walk to create a generator so we can iterate on the parts and forget about the recursive headache
    for part in mail.walk():
        # multipart are just containers, so we skip them
    if part.get_content_maintype() == 'multipart':
        continue
    
        # is this part an attachment ?
        if part.get('Content-Disposition') is None: 
        continue
    
    filename = part.get_filename()
        counter = 1
        
        # if there is no filename, we create one with a counter to avoid duplicates
        if not filename:
            filename = 'part-%03d%s' % (counter, 'bin')
        counter += 1
    
    att_path = os.path.join(detach_new, filename)  <-----------------
        
        #Check if its already there
        if not os.path.isfile(att_path) :
        # finally write the stuff
        fp = open(att_path, 'wb')
            fp.write(part.get_payload(decode=True))
            fp.close()
    M.store(num, '+FLAGS', '\\Deleted')  <-----------------
M.close()
M.logout()

Проблемы:
1.Если письмо без аттача, то оно не удаляется.
2.Если папка уже есть, то:
Traceback (most recent call last):
  File "./imap_detach_folder.py", line 19, in <module>
    os.makedirs(detach_new)
  File "/usr/lib/python2.5/os.py", line 171, in makedirs
    mkdir(name, mode)
OSError: [Errno 17] File exists: '/home/samba/shares/unique/2014-03-31/'

Вторую проблему, конечно, можно решить, запуская скрипт раз в сутки. С первой пока не разобрался.
Принимаю любые советы по улучшению данного кода.

Отредактировано kolin_k (Март 31, 2014 17:13:48)

Офлайн

#2 Апрель 1, 2014 02:42:34

pyuser
От:
Зарегистрирован: 2007-05-13
Сообщения: 658
Репутация: +  36  -
Профиль   Отправить e-mail  

Допиливание скрипта под определенную задачу. Imaplib.

У Вас отступы не правильно расставлены :(

kolin_k
Вторую проблему, конечно, можно решить, запуская скрипт раз в сутки
А можно проверять существование папки:
if not os.path.isdir(detach_new):
    os.makedirs(detach_new)
kolin_k
С первой пока не разобрался
Нужно слегка изменить логику:
#Check if any attachments at all
if mail.get_content_maintype() == 'multipart': 
    # здесь обрабатываем письмо с вложением
M.store(num, '+FLAGS', '\\Deleted')
...



Офлайн

#3 Апрель 1, 2014 08:47:16

kolin_k
Зарегистрирован: 2014-03-31
Сообщения: 6
Репутация: +  0  -
Профиль   Отправить e-mail  

Допиливание скрипта под определенную задачу. Imaplib.

pyuser
Нужно слегка изменить логику:

#Check if any attachments at all
if mail.get_content_maintype() == ‘multipart’:
# здесь обрабатываем письмо с вложением
M.store(num, ‘+FLAGS’, ‘\\Deleted’)


Наверно здесь обрабатываем письмо без вложения.
Спасибо. Сделал так:
#!/usr/bin/env python
 
import getpass, imaplib, email, os
from email import parser
 
detach_dir = '/home/samba/shares/unique'
detach_new = '/home/samba/shares/unique/%s/' % datetime.date.today()   
M = imaplib.IMAP4('mail.ru')
M.login('test@mail.ru', 'password')
M.select()
typ, data = M.search(None, 'ALL') 
if data != ['']:            
    if not os.path.isdir(detach_new):  <-----------------
        os.makedirs(detach_new)  
for num in data[0].split():
    typ, data = M.fetch(num, '(RFC822)')
    email_body = data[0][1] # getting the mail content
    mail = email.message_from_string(email_body) # parsing the mail content to get a mail object
    
    #Check if any attachments at all
    if mail.get_content_maintype() != 'multipart':
        M.store(num, '+FLAGS', '\\Deleted')   <-----------------
        continue
 
    print "["+mail["From"]+"] :" + mail["Subject"]
    
    # we use walk to create a generator so we can iterate on the parts and forget about the recursive headache
    for part in mail.walk():
        # multipart are just containers, so we skip them
    if part.get_content_maintype() == 'multipart':
        continue
    
        # is this part an attachment ?
        if part.get('Content-Disposition') is None: 
        continue
    
    filename = part.get_filename()
        counter = 1
        
        # if there is no filename, we create one with a counter to avoid duplicates
        if not filename:
            filename = 'part-%03d%s' % (counter, 'bin')
        counter += 1
    
    att_path = os.path.join(detach_new, filename)  
        
        #Check if its already there
        if not os.path.isfile(att_path) :
        # finally write the stuff
        fp = open(att_path, 'wb')
            fp.write(part.get_payload(decode=True))
            fp.close()
    M.store(num, '+FLAGS', '\\Deleted')  
M.close()
M.logout()

Отредактировано kolin_k (Апрель 1, 2014 08:52:06)

Офлайн

#4 Апрель 1, 2014 08:50:37

pyuser
От:
Зарегистрирован: 2007-05-13
Сообщения: 658
Репутация: +  36  -
Профиль   Отправить e-mail  

Допиливание скрипта под определенную задачу. Imaplib.

kolin_k
Наверно здесь обрабатываем письмо без вложения.
Для писем без вложений:
mail.get_content_maintype() != 'multipart'



Офлайн

#5 Апрель 1, 2014 08:55:24

kolin_k
Зарегистрирован: 2014-03-31
Сообщения: 6
Репутация: +  0  -
Профиль   Отправить e-mail  

Допиливание скрипта под определенную задачу. Imaplib.

За ночь пришла в голову идея дату брать из письма, а не текущую. Тогда будет более универсально. Не знаете как?
Нашел такую команду:

print mail['Date']
Выглядит так:
Tue, 01 Apr 2014 10:35:11 +0400
Как можно перевести в формат гггг-мм-дд ?

ЗЫ: Вырезал пока так:
day = mail['Date']
newday = day[5:16]
print(newday)
Вывод:
01 Apr 2014

Отредактировано kolin_k (Апрель 1, 2014 10:08:07)

Офлайн

#6 Апрель 1, 2014 10:43:58

pyuser
От:
Зарегистрирован: 2007-05-13
Сообщения: 658
Репутация: +  36  -
Профиль   Отправить e-mail  

Допиливание скрипта под определенную задачу. Imaplib.

kolin_k
Как можно перевести в формат гггг-мм-дд ?
Установите пакет dateutil
>>> from dateutil import parser
>>> parser.parse("Tue, 01 Apr 2014 10:35:11 +0400")
datetime.datetime(2014, 4, 1, 10, 35, 11, tzinfo=tzoffset(None, 14400))



Офлайн

#7 Апрель 1, 2014 11:33:26

kolin_k
Зарегистрирован: 2014-03-31
Сообщения: 6
Репутация: +  0  -
Профиль   Отправить e-mail  

Допиливание скрипта под определенную задачу. Imaplib.

dateutil установил.

from dateutil import parser
...
day = mail['Date']
newday = dateutil.parser.parse(day)
Ошибка такая:
Traceback (most recent call last):
  File "./imap_detach_folder.py", line 39, in <module>
    newday = dateutil.parser.parse(day)
NameError: name 'dateutil' is not defined

И непонятно, как строчку “datetime.datetime(2014, 4, 1, 10, 35, 11, tzinfo=tzoffset(None, 14400))” в дату превратить?


Сделал так:
day = mail['Date']
newday = parser.parse(day).date()
print(newday)

Отредактировано kolin_k (Апрель 1, 2014 11:56:19)

Офлайн

#8 Апрель 1, 2014 12:42:53

kolin_k
Зарегистрирован: 2014-03-31
Сообщения: 6
Репутация: +  0  -
Профиль   Отправить e-mail  

Допиливание скрипта под определенную задачу. Imaplib.

Вроде все получилось. Остался один косяк, но это уже наверно не сюда. Хотя если будут мысли, с радостью прочитаю.
Косяк. Если выкладывать аттачи в одну кучу, без создании папки, то они спокойно удаляются с шары из винды, согласно выданным правам.
А вот если, как сейчас раскидывать по папкам, то файлы не удалить. Верней вроде удалил, а обновил папку, файлы снова там. Вобщем пока думаю, почему так.

Итог скрипта такой:

#!/usr/bin/env python
import getpass, imaplib, email, os, datetime
from email import parser
from dateutil import parser
M = imaplib.IMAP4('mail.ru')
M.login('test@mail.ru', 'password')
M.select()
typ, data = M.search(None, 'ALL')
for num in data[0].split():
    typ, data = M.fetch(num, '(RFC822)')
    email_body = data[0][1] # getting the mail content
    mail = email.message_from_string(email_body) # parsing the mail content to get a mail object
    #Check if any attachments at all
    if mail.get_content_maintype() != 'multipart':
        M.store(num, '+FLAGS', '\\Deleted')
        continue
    # we use walk to create a generator so we can iterate on the parts and forget about the recursive headache
    for part in mail.walk():
        # multipart are just containers, so we skip them
        if part.get_content_maintype() == 'multipart':
            day = str(parser.parse(mail['Date']).date())
            detach_dir = '/home/samba/shares/unique/' + day + '/'
            if not os.path.isdir(detach_dir):
                os.makedirs(detach_dir)
            continue
        # is this part an attachment ?
        if part.get('Content-Disposition') is None:
            continue
        filename = part.get_filename()
        counter = 1
        # if there is no filename, we create one with a counter to avoid duplicates
        if not filename:
            filename = 'part-%03d%s' % (counter, 'bin')
            counter += 1
        att_path = os.path.join(detach_dir, filename)
        #Check if its already there
        if not os.path.isfile(att_path) :
            # finally write the stuff
            fp = open(att_path, 'wb')
            fp.write(part.get_payload(decode=True))
            fp.close()
    M.store(num, '+FLAGS', '\\Deleted')
M.close()
M.logout()

Офлайн

#9 Апрель 1, 2014 17:12:12

kolin_k
Зарегистрирован: 2014-03-31
Сообщения: 6
Репутация: +  0  -
Профиль   Отправить e-mail  

Допиливание скрипта под определенную задачу. Imaplib.

pyuser
Может знаете, как выкладывать файл на виндовую шару в этом скрипте?

Офлайн

#10 Апрель 2, 2014 03:29:37

pyuser
От:
Зарегистрирован: 2007-05-13
Сообщения: 658
Репутация: +  36  -
Профиль   Отправить e-mail  

Допиливание скрипта под определенную задачу. Imaplib.

kolin_k
day = str(parser.parse(mail['Date']).date())
Вам уже пора научиться help'ом пользоваться, у объектов datetime есть метод strftime
kolin_k
Может знаете, как выкладывать файл на виндовую шару в этом скрипте?
Я в windows работаю, для меня сохранение в расшаренную папку ни чем не отличается от сохранения в локальную.



Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version