Added imap with pop protocal for email retrive

This commit is contained in:
Gangadhar Kadam 2015-11-24 18:11:42 +05:30
parent abf04d1d05
commit 2f51b3efd0
4 changed files with 136 additions and 20 deletions

View file

@ -33,11 +33,45 @@ email_defaults = {
},
};
email_defaults_imap = {
"GMail": {
"pop3_server": "imap.gmail.com"
},
"Outlook.com": {
"pop3_server": "imap.live.com"
},
"Yahoo Mail": {
"pop3_server": "imap.mail.yahoo.com"
},
"Yandex.Mail": {
"pop3_server": "imap.yandex.com"
},
};
frappe.ui.form.on("Email Account", {
service: function(frm) {
$.each(email_defaults[frm.doc.service], function(key, value) {
frm.set_value(key, value);
})
if (frm.doc.use_imap) {
$.each(email_defaults_imap[frm.doc.service], function(key, value) {
frm.set_value(key, value);
})
}
},
use_imap: function(frm) {
console.log("in use imap");
if (frm.doc.use_imap) {
$.each(email_defaults_imap[frm.doc.service], function(key, value) {
frm.set_value(key, value);
})
}
else{
$.each(email_defaults[frm.doc.service], function(key, value) {
frm.set_value(key, value);
})
}
},
email_id: function(frm) {
if(!frm.doc.email_account_name) {

View file

@ -222,6 +222,30 @@
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"depends_on": "",
"fieldname": "use_imap",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"in_filter": 0,
"in_list_view": 0,
"label": "Use Imap",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"unique": 0
},
{
"allow_on_submit": 0,
"bold": 0,
@ -808,13 +832,14 @@
"hide_heading": 0,
"hide_toolbar": 0,
"icon": "icon-inbox",
"idx": 0,
"in_create": 0,
"in_dialog": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2015-11-16 06:29:45.876335",
"modified": "2015-11-24 17:45:31.001113",
"modified_by": "Administrator",
"module": "Email",
"name": "Email Account",

View file

@ -9,13 +9,15 @@ from frappe.utils import validate_email_add, cint, get_datetime, DATE_FORMAT, st
from frappe.utils.user import is_system_user
from frappe.utils.jinja import render_template
from frappe.email.smtp import SMTPServer
from frappe.email.receive import POP3Server, Email
from frappe.email.receive import POP3Server,Email
from poplib import error_proto
import re
import imaplib
import markdown2, re
from dateutil.relativedelta import relativedelta
from datetime import datetime, timedelta
class SentEmailInInbox(Exception): pass
class SentEmailInInbox(Exception): pass # imap
class error(Exception): pass # imap
class EmailAccount(Document):
def autoname(self):
@ -30,7 +32,7 @@ class EmailAccount(Document):
self.name = self.email_account_name
def validate(self):
"""Validate email id and check POP3 and SMTP connections is enabled."""
"""Validate email id and check POP3/IMAP and SMTP connections is enabled."""
if self.email_id:
validate_email_add(self.email_id, True)
@ -102,7 +104,8 @@ class EmailAccount(Document):
"host": self.pop3_server,
"use_ssl": self.use_ssl,
"username": getattr(self, "login_id", None) or self.email_id,
"password": self.password
"password": self.password,
"use_imap":self.use_imap
}
if not self.pop3_server:
@ -111,7 +114,7 @@ class EmailAccount(Document):
pop3 = POP3Server(frappe._dict(args))
try:
pop3.connect()
except error_proto, e:
except (error_proto,imaplib.IMAP4.error) , e:
frappe.throw(e.message)
return pop3
@ -315,14 +318,18 @@ def get_append_to(doctype=None, txt=None, searchfield=None, start=None, page_len
if not txt: txt = ""
return [[d] for d in frappe.get_hooks("email_append_to") if txt in d]
def pull(now=False):
def pull(now=True):
"""Will be called via scheduler, pull emails from all enabled POP3 email accounts."""
import frappe.tasks
print "in pull method "
for email_account in frappe.get_list("Email Account", filters={"enable_incoming": 1}):
print email_account
#frappe.tasks.pull_from_email_account(frappe.local.site, email_account.name)
if now:
print "in now"
frappe.tasks.pull_from_email_account(frappe.local.site, email_account.name)
else:
print "not now"
frappe.tasks.pull_from_email_account.delay(frappe.local.site, email_account.name)
def notify_unreplied():

View file

@ -3,7 +3,7 @@
from __future__ import unicode_literals
import time
import _socket, poplib
import _socket, poplib,imaplib
import frappe
from frappe import _
from frappe.utils import extract_email_id, convert_utc_to_user_timezone, now, cint, cstr, strip
@ -36,6 +36,31 @@ class POP3Server:
def connect(self):
"""Connect to **Email Account**."""
responce = self.connect_imap() if cint(self.settings.use_imap) else self.connect_pop()
return responce
def connect_imap(self):
#this method return imap connection
try:
if cint(self.settings.use_ssl):
self.imap = Timed_IMAP4_SSL(self.settings.host, timeout=frappe.conf.get("pop_timeout"))
else:
self.imap = Timed_IMAP4(self.settings.host, timeout=frappe.conf.get("pop_timeout"))
self.imap.login(self.settings.username,self.settings.password)
# connection established!
return True
except _socket.error:
# Invalid mail server -- due to refusing connection
frappe.msgprint(_('Invalid Mail Server. Please rectify and try again.'))
raise
except :
frappe.msgprint(_('Invalid User Name or Support Password. Please rectify and try again.'))
raise
def connect_pop(self):
#this method return pop connection
try:
if cint(self.settings.use_ssl):
self.pop = Timed_POP3_SSL(self.settings.host, timeout=frappe.conf.get("pop_timeout"))
@ -75,8 +100,14 @@ class POP3Server:
# track if errors arised
self.errors = False
self.latest_messages = []
pop_list = self.pop.list()[1]
num = num_copy = len(pop_list)
# if section code below is for imap and else part is for pop3
if cint(self.settings.use_imap):
self.imap.select("Inbox")
responce, message = self.imap.uid('search',None, "UNSEEN") # search and return Uids
email_list = message[0].split()
else:
email_list = self.pop.list()[1]
num = num_copy = len(email_list)
# WARNING: Hard coded max no. of messages to be popped
if num > 20: num = 20
@ -86,20 +117,24 @@ class POP3Server:
self.max_email_size = cint(frappe.local.conf.get("max_email_size"))
self.max_total_size = 5 * self.max_email_size
for i, pop_meta in enumerate(pop_list):
for i, pop_meta in enumerate(email_list):
# do not pull more than NUM emails
if (i+1) > num:
break
try:
self.retrieve_message(pop_meta, i+1)
# if section code below is for imap and else part is for pop3
if cint(self.settings.use_imap):
self.retrieve_message(pop_meta)
else:
self.retrieve_message(pop_meta, i+1)
except (TotalSizeExceededError, EmailTimeoutError, LoginLimitExceeded):
break
# WARNING: Mark as read - message number 101 onwards from the pop list
# This is to avoid having too many messages entering the system
num = num_copy
if num > 100 and not self.errors:
if num > 100 and not self.errors and not cint(self.settings.use_imap):
for m in xrange(101, num+1):
self.pop.dele(m)
@ -112,17 +147,25 @@ class POP3Server:
finally:
# no matter the exception, pop should quit if connected
self.pop.quit()
if cint(self.settings.use_imap):
self.imap.logout()
else:
self.pop.quit()
return self.latest_messages
def retrieve_message(self, pop_meta, msg_num):
def retrieve_message(self, pop_meta,msg_num=None):
incoming_mail = None
try:
self.validate_pop(pop_meta)
msg = self.pop.retr(msg_num)
# if section code below is for imap and else part is for pop3
if cint(self.settings.use_imap):
status,message = self.imap.uid('fetch', pop_meta, '(RFC822)')
self.latest_messages.append(message[0][1])
else:
msg = self.pop.retr(msg_num)
self.latest_messages.append(b'\n'.join(msg[1]))
self.latest_messages.append(b'\n'.join(msg[1]))
except (TotalSizeExceededError, EmailTimeoutError):
# propagate this error to break the loop
@ -140,9 +183,11 @@ class POP3Server:
self.errors = True
frappe.db.rollback()
self.pop.dele(msg_num)
if not cint(self.settings.use_imap):
self.pop.dele(msg_num)
else:
self.pop.dele(msg_num)
if not cint(self.settings.use_imap):
self.pop.dele(msg_num)
def has_login_limit_exceeded(self, e):
return "-ERR Exceeded the login limit" in strip(cstr(e.message))
@ -355,3 +400,8 @@ class Timed_POP3(TimerMixin, poplib.POP3):
class Timed_POP3_SSL(TimerMixin, poplib.POP3_SSL):
_super = poplib.POP3_SSL
class Timed_IMAP4(TimerMixin, imaplib.IMAP4):
_super = imaplib.IMAP4
class Timed_IMAP4_SSL(TimerMixin, imaplib.IMAP4_SSL):
_super = imaplib.IMAP4_SSL