Skip to content

Instantly share code, notes, and snippets.

@asyndrige
Created May 19, 2016 18:42
Show Gist options
  • Save asyndrige/17d330f1a532264431120a363a93fc1e to your computer and use it in GitHub Desktop.
Save asyndrige/17d330f1a532264431120a363a93fc1e to your computer and use it in GitHub Desktop.
# coding=utf-8
import imaplib
import os
import email
import base64
from datetime import datetime
from importlib import import_module
from email.header import decode_header
from django.db import transaction
from lib.models import FileKoodoo
from base.functions import email_re
from base.functions import model_from_cache
def get_connection(box):
if box.ssl:
m = imaplib.IMAP4_SSL(box.server, box.port)
else:
m = imaplib.IMAP4(box.server, box.port)
m.login(box.login, box.password)
return m
@transaction.commit_on_success
def move_to_folder(box, message, folder, connection=None, uid=None):
u""" move message to folder """
message.folder = folder
message.save(update_fields=('folder',))
if connection is None:
connection = get_connection(box)
connection.select(folder.name)
if uid is None:
result, uids = connection.uid('search', 'HEADER', 'Message-ID', message.imap_id)
if result != 'ОК':
raise Exception(u'not find message in mail folder by message-id')
uid = uids[0]
result = connection.uid('copy', uid, folder.name)[0]
if result == 'OK':
connection.uid('store', uid, '+FLAGS', '\\Deleted')
def mail_to_photoarchive(message_object, n_loss, document_id, ent_id, obj_id, type_id):
u""" save mail into photoarchive"""
# Прикрепить сообщения в старый фотоархив
#file_path = 'dfsroot/CO/App/ScanDoc04/SED/%s' % datetime.now().strftime('%Y/%m/%d') //Нерабочий ScanDoc
file_path = 'dfsroot/CO/App/ScanDoc05/SED/%s' % datetime.now().strftime('%Y/%m/%d')
file_name = 'mail_%s.eml' % message_object.id
file_path_save = '/mnt/' + file_path
file_path_save_full = file_path_save + '/' + file_name
if not os.path.exists(file_path_save):
os.makedirs(file_path_save)
from io import BufferedWriter, FileIO
with BufferedWriter(FileIO(file_path_save_full, "wb")) as dest:
dest.write(base64.b64decode(message_object.raw_body))
new_file = FileKoodoo(file_type_id=type_id,
file_path=('//koodoo.ru/%s/%s' % (file_path, file_name)).replace('/', '\\'),
file_size=os.path.getsize(file_path_save_full),
file_name_original='mail_%s' % message_object.id,
n_loss=n_loss,
document_id=document_id,
object_ent_id=ent_id,
object_obj_id=obj_id,
date_typing=datetime.now(),
created_from=u'py_mail')
new_file.save()
def get_box_manager(box, user=None, folder=None, email_message=None, request=None):
u""" get manager class """
module_name = 'mailer.box_managers.box_%s' % box.id
module = import_module(module_name)
return module.BoxManager(user, folder, email_message, request, box)
def get_model(box_id, model_name):
u""" Достает модель из кэша """
return model_from_cache('mailer', '%s%s' % (model_name, box_id))
def decode_value(value_raw, message_charset=None):
u""" return decoded raw value.
if value is multi-row, decode row-by-row """
if message_charset and message_charset != 'utf-8':
value_raw = value_raw.decode(message_charset)
lines = []
for w, e in decode_header(value_raw):
if e is not None and e != 'uft-8':
w = w.decode(e)
lines.append(w)
return u' '.join(lines)
@transaction.commit_on_success
def process_email(m, mail_uid, folder, Message, box_manager):
# get raw content
result, data = m.uid('fetch', mail_uid, '(RFC822)')
raw_mail = data[0][1]
mail = email.message_from_string(raw_mail)
# parse mail
mail_data = parse_message(mail)
if mail_data is None:
print 'mail_data is None'
return
imap_id = mail_data['imap_id']
subject = mail_data['subject']
sender = mail_data['sender']
email_body = mail_data['email_body']
# if message already uploaded and marked as unseen
if Message.objects.filter(imap_id=imap_id).exists():
m.uid('store', mail_uid, '+FLAGS', '\\Seen')
return
# create object
msg_object = Message(folder=folder,
raw_body=base64.b64encode(raw_mail),
subject=subject,
sender=sender,
imap_id=imap_id,
body=email_body,
deleted=False)
msg_object.save()
conf = open(os.path.join('/', 'home', 'www', 'py_docflow', 'fail.log'), 'a')
conf.write(subject)
conf.write("/")
conf.write(sender)
conf.write("------------------------------------------------------------\n")
conf.close()
# if message move to another folder in box_manager, unseen error
try:
# mark seen
m.uid('store', mail_uid, '+FLAGS', '\\Seen')
# send signal create document
box_manager.message_created(msg_object, m, mail_uid)
m.expunge()
except:
m.uid('store', mail_uid, '-FLAGS', '\\Seen')
raise
def get_emails(box):
u""" get emails from server and store to database """
m = get_connection(box)
i = 0
Message = get_model(box.id, 'Message')
Folder = get_model(box.id, 'Folder')
# Получение объекта BoxManager
box_manager = get_box_manager(box)
for folder in Folder.objects.filter(download=True):
result, message = m.select(folder.name)
if result != 'OK':
raise Exception(message)
result, data = m.uid('search', None, 'UNSEEN') # UNSEEN
mail_uids = data[0].split()
for mail_uid in mail_uids:
if i >= 20:
break
process_email(m, mail_uid, folder, Message, box_manager)
i += 1
m.close()
m.logout()
return i
def parse_message(mail):
u""" parse message and get message items """
subject_raw = mail['subject']
subject, message_charset = decode_header(subject_raw)[0]
if message_charset:
subject = subject.decode(message_charset)
subject = subject[:249]
imap_id = mail['message-id']
sender = mail['from']
if sender is None:
return None
sender = email_re.search(sender).group()
email_body = None
if mail.is_multipart():
for part in mail.walk():
if part.get_content_type() == 'text/plain':
email_body = part.get_payload(decode=True)
charset = part.get_content_charset()
if charset:
email_body = email_body.decode(charset)
break
else:
email_body = mail.get_payload(decode=True)
charset = mail.get_content_charset()
if charset is not None:
email_body = email_body.decode(charset)
return {'subject': subject,
'imap_id': imap_id,
'sender': sender,
'email_body': email_body}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment