Guest User

Untitled

a guest
Nov 23rd, 2017
481
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 27.24 KB | None | 0 0
  1. #########################################################################
  2. # -*- coding: utf-8 -*- #
  3. #""" #
  4. # poweremail account #
  5. # ~~~~~~~~ #
  6. #Poweremail is the email tool for openerp - "made with good intentions" #
  7. #:copyright: (c) 2009-2010 by Sharoon Thomas #
  8. #:copyright: (c) 2011 by Openlabs Technologies & Consulting (P) Limited.#
  9. #:license: GPL, see LICENSE for more details. #
  10. #""" #
  11. #########################################################################
  12.  
  13. import string
  14. import re
  15. import smtplib
  16. import poplib
  17. import imaplib
  18. import base64
  19. import time
  20. import datetime
  21.  
  22. from email import Encoders, message_from_string
  23. from email.mime.base import MIMEBase
  24. from email.mime.multipart import MIMEMultipart
  25. from email.mime.text import MIMEText
  26. from email.header import decode_header, Header
  27. from email.utils import formatdate
  28.  
  29. from osv import osv, fields
  30. from tools.translate import _
  31. import netsvc
  32. import tools
  33. import helpers
  34.  
  35.  
  36. class Account(osv.osv):
  37. """
  38. Email Account Settings
  39.  
  40. .. note:: The web client does not show a valid message when the
  41. 'Test Incoming Connection' is done
  42.  
  43. .. warning:: The email usernames and passwords are stored as plain text in
  44. the database. Store them at your own risk.
  45. """
  46. _name = "poweremail.account"
  47. _description = "Email Accounts"
  48.  
  49. _known_content_types = [
  50. 'multipart/mixed',
  51. 'multipart/alternative',
  52. 'multipart/related',
  53. 'text/plain',
  54. 'text/html'
  55. ]
  56.  
  57. _columns = {
  58. 'name': fields.char('Name',size=64, required=True, readonly=True,
  59. select=True, states={'draft':[('readonly', False)]}),
  60. 'user': fields.many2one('res.users', 'Owner', required=True,
  61. readonly=True, states={'draft':[('readonly', False)]}),
  62. 'email_id': fields.char('Email ID', size=120, required=True,
  63. readonly=True, states={'draft':[('readonly', False)]} ,
  64. help="eg : yourname@yourdomain.com "),
  65. 'smtp_server': fields.char('Outgoing Mail Server', size=120,
  66. required=True,readonly=True, states={'draft':[('readonly',
  67. False)]}, help="eg : smtp.gmail.com "),
  68. 'smtp_port': fields.integer('SMTP Port', size = 64, required = True,
  69. readonly=True, states={'draft':[('readonly', False)]},
  70. help="eg : SMTP-587 "),
  71. 'smtp_username': fields.char('User Name', size=120, required=False,
  72. readonly=True, states={'draft':[('readonly', False)]}),
  73. 'smtp_password': fields.char( 'Password', size=20, invisible=True,
  74. required=False, readonly=True,states={
  75. 'draft':[('readonly', False)]}),
  76. 'smtp_use_tls': fields.boolean('Use TLS',
  77. states={'draft':[('readonly', False)]},readonly=True),
  78. 'smtp_use_ssl':fields.boolean('Use SSL/TLS (only in python 2.6)',
  79. states={'draft':[('readonly', False)]}, readonly=True),
  80. 'send_preference': fields.selection(
  81. [
  82. ('html', 'HTML otherwise Text'),
  83. ('text', 'Text otherwise HTML'),
  84. ('both', 'Both HTML & Text')
  85. ], 'Mail Format', required=True),
  86. 'incoming_server': fields.char('Incoming mail server', size = 100,
  87. readonly = True,states = {'draft':[('readonly', False)]},
  88. help = "eg : imap.gmail.com "),
  89. 'incoming_port': fields.integer('Port', readonly = True,
  90. states = {'draft':[('readonly', False)]},
  91. help="For example IMAP: 993,POP3: 995 "),
  92. 'incoming_username': fields.char( 'User Name', size = 100,
  93. readonly = True, states={'draft':[('readonly', False)]}),
  94. 'incoming_password': fields.char('Password', size = 100,
  95. readonly = True,
  96. states = {'draft':[('readonly', False)]}),
  97. 'incoming_protocol': fields.selection(
  98. [
  99. ('imap', 'IMAP'),
  100. ('pop3', 'POP3')
  101. ], 'Server Type', readonly = True,
  102. states={'draft':[('readonly', False)]}),
  103. 'incoming_use_ssl': fields.boolean( 'Use SSL', readonly=True,
  104. states={
  105. 'draft':[('readonly', False)]
  106. }),
  107. 'imap_folder': fields.char('Folder', readonly=True, size=100,
  108. help="Folder to be used for downloading IMAP mails"
  109. "Click on adjacent button to select from a list of folders"),
  110. 'last_downloaded_mail': fields.integer('Last Downloaded Mail',
  111. readonly=True),
  112. 'use_complete_download': fields.boolean(
  113. 'First Receive headers, then download mail',
  114. help="Download complete email(else only headers are downloaded)"),
  115. 'use_download_attachments': fields.boolean(
  116. 'Download attachments automatically'),
  117. 'is_shared_account': fields.boolean('Company Mail A/c', readonly=True,
  118. help="Select if this mail account does not belong" \
  119. "to specific user but the organisation as a whole." \
  120. "eg : info@somedomain.com",
  121. states={'draft':[('readonly', False)]}),
  122. 'state': fields.selection([
  123. ('draft', 'Initiated'),
  124. ('suspended', 'Suspended'),
  125. ('approved', 'Approved')],
  126. 'Account Status', required=True, readonly=True),
  127. }
  128.  
  129. def default_name(self, cursor, user, context = None):
  130. "Returns the default value for name"
  131. user_obj = self.pool.get('res.users')
  132. user = user_obj.browse(cursor, user, user, context)
  133. return user.name
  134.  
  135. _defaults = {
  136. 'name': default_name,
  137. 'smtp_use_ssl': lambda * a: True,
  138. 'state': lambda * a: 'draft',
  139. 'user': lambda obj, cursor, user, context:user,
  140. 'incoming_protocol': lambda *a: 'imap',
  141. 'incoming_use_ssl': lambda *a: True,
  142. 'last_downloaded_mail': lambda *a: 0,
  143. 'use_complete_download': lambda *a: True,
  144. 'use_download_attachments': lambda *a: True,
  145. 'send_preference': lambda *a: 'html',
  146. 'smtp_use_tls': lambda *a: True,
  147. }
  148.  
  149. _sql_constraints = [('email_uniq', 'unique (email_id)',
  150. 'Another setting already exists with this email ID !')]
  151.  
  152. def on_change_emailid(self, cursor, user, id, email_id=None,
  153. smtp_username=None, incoming_username=None, context=None):
  154. """
  155. Called when the email ID field changes.
  156.  
  157. UI enhancement
  158. Writes the same email value to the smtpusernameif
  159. account.incoming_server and account.incoming_port
  160. and incoming username
  161. """
  162. res = {'state': 'draft'}
  163. if not smtp_username:
  164. res['smtp_username'] = email_id
  165. if not incoming_username:
  166. res['incoming_username'] = email_id
  167. return {'value': res}
  168.  
  169. def _get_outgoing_server(self, cursor, user, accountid, context=None):
  170. """
  171. Returns the Out Going Connection (SMTP) object
  172.  
  173. .. warning:: DO NOT USE except_osv IN THIS METHOD
  174. :param cursor: Database Cursor
  175. :param user: ID of current user
  176. :param account_id: ID of current object for which connection is required
  177. :param context: Context
  178.  
  179. :return: SMTP server object or Exception
  180. """
  181. if type(active_id) == list:
  182. active_id = active_id[0]
  183. print active_id
  184. this_object = self.browse(cursor, user, accountid, context)
  185. if not this_object:
  186. raise Exception(_("Account not found"))
  187. if not (this_object.smtp_server and this_object.smtp_port):
  188. raise Exception(_("SMTP SERVER or PORT not specified"))
  189. if this_object.smtp_use_ssl:
  190. server = smtplib.SMTP_SSL(this_object.smtp_server,
  191. this_object.smtp_port)
  192. else:
  193. server = smtplib.SMTP(this_object.smtp_server,
  194. this_object.smtp_port)
  195. if this_object.smtp_use_tls:
  196. server.ehlo()
  197. server.starttls()
  198. server.ehlo()
  199. if server.has_extn('AUTH') or \
  200. this_object.smtp_username or \
  201. this_object.smtp_password:
  202. server.login(
  203. this_object.smtp_username.encode('UTF-8'),
  204. this_object.smtp_password.encode('UTF-8')
  205. )
  206. return server
  207.  
  208. def check_outgoing_connection(self, cursor, user, accountid, context=None):
  209. """
  210. checks SMTP credentials and confirms if outgoing connection works
  211. (Attached to button)
  212. :param cursor: Database Cursor
  213. :param user: ID of current user
  214. :param ids: list of ids of current object for
  215. which connection is required
  216. :param context: Context
  217. """
  218. try:
  219. self._get_outgoing_server(cursor, user, accountid, context)
  220. raise osv.except_osv(
  221. _('SMTP Connection'),
  222. _("SMTP Test Connection Was Successful")
  223. )
  224. except osv.except_osv, success_message:
  225. raise success_message
  226. except Exception, error:
  227. raise osv.except_osv(
  228. _("Out going connection test failed"),
  229. _("Reason: %s") % error
  230. )
  231.  
  232. def _get_imap_server(self, record):
  233. """
  234. :param record: Browse record of current connection
  235. :return: IMAP or IMAP_SSL object
  236. """
  237.  
  238. if record.incoming_use_ssl:
  239. server = imaplib.IMAP4_SSL(record.incoming_server,
  240. record.incoming_port)
  241. else:
  242. server = imaplib.IMAP4(record.incoming_server, record.incoming_port)
  243. #Now try to login
  244. server.login(record.incoming_username, record.incoming_password)
  245. return server
  246.  
  247.  
  248. def _get_pop3_server(self, record):
  249. """
  250. :param record: Browse record of current connection
  251. :return: POP3 or POP3_SSL object
  252. """
  253. if record.incoming_use_ssl:
  254. server = poplib.POP3_SSL(record.incoming_server,
  255. record.incoming_port)
  256. else:
  257. server = poplib.POP3(record.incoming_server, record.incoming_port)
  258. server.user(record.incoming_username)
  259. server.pass_(record.incoming_password)
  260. return server
  261.  
  262. def _get_incoming_server(self, cursor, user, account_id, context=None):
  263. """
  264. Returns the Incoming Server object
  265. Could be IMAP/IMAP_SSL/POP3/POP3_SSL
  266.  
  267. .. warning:: DO NOT USE except_osv IN THIS METHOD
  268.  
  269. :param cursor: Database Cursor
  270. :param user: ID of current user
  271. :param account_id: ID of current object for which connection is required
  272. :param context: Context
  273.  
  274. :return: IMAP/POP3 server object or Exception
  275. """
  276. if type(account_id) == list:
  277. account_id = account_id[0]
  278. #this_object = self.browse(cursor, user, account_id, context)
  279. #print'aaaa'
  280. #print this_object
  281. #print account_id
  282. if not this_object:
  283. raise Exception(
  284. _("Account not found")
  285. )
  286.  
  287. if not this_object.incoming_server:
  288. raise Exception(_("Incoming server is not defined"))
  289. if not this_object.incoming_port:
  290. raise Exception(_("Incoming port is not defined"))
  291. if not this_object.incoming_username:
  292. raise Exception(_("Incoming server user name is not defined"))
  293. if not this_object.incoming_username:
  294. raise Exception(_("Incoming server password is not defined"))
  295.  
  296. if this_object.incoming_protocol == 'imap':
  297. server = self._get_imap_server(this_object)
  298. elif this_object.incoming_protocol == 'pop3':
  299. server = self._get_pop3_server(this_object)
  300. return server
  301.  
  302. def check_incoming_connection(self, cursor, user, accountid, context=None):
  303. """
  304. checks incoming credentials and confirms if outgoing connection works
  305. (Attached to button)
  306. :param cursor: Database Cursor
  307. :param user: ID of current user
  308. :param ids: list of ids of current object for
  309. which connection is required
  310. :param context: Context
  311. """
  312. try:
  313. self._get_incoming_server(cursor, user, accountid, context)
  314. raise osv.except_osv(
  315. _("Incoming Connection"),
  316. _("Incoming Test Connection Was Successful"))
  317. except osv.except_osv, success_message:
  318. raise success_message
  319. except Exception, error:
  320. raise osv.except_osv(
  321. _("Incoming connection test failed"),
  322. _("Reason: %s") % error)
  323.  
  324. def approve(self, cursor, user, accountid, context={}):
  325. """
  326. Approves the given mail account
  327. """
  328. print accountid
  329. print context
  330. return self.write(cursor, user, accountid,
  331. {'state':'approved'},
  332. context=context)
  333.  
  334. def send_mail(self, cursor, user, id, recepients, message, context=None):
  335. """
  336. Sends an email through a core account
  337.  
  338. :param id: ID of the core account
  339. :param recepients: A list of email ids in strings
  340. :param message: MIMEMessage
  341. :param context: Open ERP Context
  342. :return: True if successful, else raises exception
  343. """
  344. if context is None:
  345. context = {}
  346. assert type(id) in (int, long)
  347. account = self.browse(cursor, user, id, context)
  348.  
  349. server = self._get_outgoing_server(cursor, user, id, context)
  350. message['From'] = Header(account.name, 'utf-8').encode()
  351. message['Organisation'] = tools.ustr(account.user.is_shared_account_id.name)
  352. addresses = self.split_to_ids(','.join(recepients))
  353. server.sendmail(message['From'], addresses, message.as_string())
  354. server.close()
  355. return True
  356.  
  357. def save_to_mailbox(self, cursor, user, message, account_id, message_id,
  358. is_new_mail, read, context=None):
  359. """
  360. Save Headers into mail
  361. :param message: Email Message object
  362. :param account_id: ID of the account
  363. :param message_id: ID of the message on server
  364. :param read: Boolean to indicate if the mail is read
  365. :param context: Context of Open ERP
  366. """
  367. mail_obj = self.pool.get('poweremail.mailbox')
  368. return mail_obj.from_email(
  369. cursor, user, is_new_mail, message_id,
  370. {
  371. 'state':read and 'read' or 'unread',
  372. 'server_ref':message_id,
  373. 'pem_account_id':account_id
  374. },
  375. message, context)
  376.  
  377. def update_mail(self, cursor, user, message, account_id, message_id, read,
  378. mailbox_mail_id, context=None):
  379. """
  380. Complete an existing email
  381. :param message: Email Message object
  382. :param account_id: ID of the account
  383. :param message_id: ID of the message on server
  384. :param read: Boolean to indicate if the mail is read
  385. :param mailbox_mail_id: ID of mail which needs updation
  386. :param context: Context of Open ERP
  387. """
  388. mail_obj = self.pool.get('poweremail.mailbox')
  389. return mail_obj.from_email(
  390. cursor, user, mailbox_mail_id,
  391. {
  392. 'state':read and 'read' or 'unread',
  393. 'server_ref':message_id,
  394. 'pem_account_id':account_id
  395. },
  396. message, context)
  397.  
  398. def _receive_mails_imap(self, account, message_id, server,
  399. header_only=False):
  400. """
  401. Receives mail from imap
  402. :param account: Browse record for core account
  403. :param message_id: ID of message on server
  404. :param server: IMAP/IMAP_SSL server object with folder selected
  405. :param header_only: If only header has to be downloaded?
  406. :return: tuple of (email(message), seen (bool))
  407. """
  408. if header_only:
  409. typ, data = server.fetch(
  410. str(message_id),
  411. '(FLAGS BODY.PEEK[HEADER])'
  412. )
  413. else:
  414. typ, data = server.fetch(
  415. str(message_id),
  416. '(FLAGS RFC822)'
  417. )
  418. # Notes:
  419. # data comes in a list [('PART1','PART2')]
  420. # Eg: [('FLAGS', 'RFC822')]
  421. return message_from_string(data[0][1]), ('/Seen' in data[0][0])
  422.  
  423. def _receive_mails_pop(self, account, message_id, server, header_only=False):
  424. """
  425. Receives mail from pop
  426. :param account: Browse record for core account
  427. :param message_id: ID of message on server
  428. :param server: POP/POP_SSL server object with folder selected
  429. :param header_only: If only header has to be downloaded?
  430. :return: tuple of (email(message), seen (bool))
  431. """
  432. if header_only:
  433. resp, message, octet = server.top(message_id, 20)
  434. else:
  435. resp, message, octet = server.retr(message_id)
  436. return message_from_string(''.join(message, "\n")), False
  437.  
  438. def receive_mails(self, cursor, user, ids, context=None):
  439. """
  440. Receives emails for the given accounts
  441. """
  442. for account in self.browse(cursor, user, ids, context):
  443. server = self._get_incoming_server(cursor, user, account.id,
  444. context)
  445.  
  446. if account.incoming_protocol == 'imap':
  447. typ, msg_count = server.select('"%s"' % account.imap_folder)
  448. if account.last_downloaded_mail < int(msg_count[0]):
  449. for message_id in xrange(
  450. account.last_downloaded_mail + 1,
  451. int(msg_count[0]) + 1):
  452. message, seen = self._receive_mails_imap(account,
  453. message_id, server, account.use_download_attachments
  454. )
  455. self.save_to_mailbox(cursor, user, message, account.id,
  456. message_id, True, seen, context)
  457. self.write(cursor, user, account.id,
  458. {'last_downloaded_mail':message_id}, context)
  459. else:
  460. # POP3
  461. if account.last_downloaded_mail < server.stat()[0]:
  462. for message_id in xrange(
  463. account.last_downloaded_mail + 1, server.stat()[0] + 1):
  464. message, seen = self._receive_mails_pop(account,
  465. message_id, server, account.rec_headers_den_mail)
  466. self.save_to_mailbox(cursor, user, message, account.id,
  467. message_id, True, seen, context)
  468. self.write(cursor, user, account.id,
  469. {'last_downloaded_mail':message_id}, context)
  470. return True
  471.  
  472. def send_receive(self, cursor, user, ids, context=None):
  473. """
  474. Typical Send-Receive funtionality
  475. """
  476. mailbox_obj = self.pool.get('poweremail.mailbox')
  477. self.receive_mails(cursor, user, ids, context)
  478. for id in ids:
  479. mailbox_obj.send_all_mail(cursor, user, [], context=account_id)
  480. return True
  481.  
  482. def get_mailbody(self, cursor, user, message_id, account, server_ref,
  483. context=None):
  484.  
  485. if account:
  486. if account.incoming_server and account.incoming_port \
  487. and account.incoming_username and account.incoming_password:
  488. if account.incoming_protocol == 'imap' \
  489. and account.imap_folder:
  490. server = self._get_incoming_server(cursor, user, account.id,
  491. context)
  492. if account.incoming_protocol == 'imap':
  493. typ, msg_count = server.select('"%s"' % account.imap_folder)
  494. message, seen = self._receive_mails_imap(account,
  495. server_ref, server)
  496. self.save_to_mailbox(cursor, user, message, account.id,
  497. message_id, False, seen, context)
  498. else:
  499. # POP3
  500. message, seen = self._receive_mails_pop(account,
  501. message_id, account.use_complete_download)
  502.  
  503. self.save_to_mailbox(cursor, user, message, account.id,
  504. message_id, False, seen, context)
  505.  
  506. def get_fullmail(self, cursor, user, mailid, context=None):
  507.  
  508. mailbox_obj = self.pool.get('poweremail.mailbox')
  509. server_ref = mailbox_obj.read(cursor, user, mailid, ['server_ref'],
  510. context)['server_ref']
  511. id = mailbox_obj.read(cursor, user, mailid, ['pem_account_id'],
  512. context)['pem_account_id'][0]
  513. account = self.browse(cursor, user, id, context)
  514. self.get_mailbody(cursor, user, mailid, account, server_ref, context)
  515.  
  516. Account()
  517.  
  518.  
  519. class PoweremailSelectIMAPFolder(osv.osv_memory):
  520. _name = "poweremail.select_imap_folder"
  521. _description = "Shows a list of IMAP folders"
  522.  
  523. def make_readable(self, imap_folder):
  524. """
  525. We consider imap_folder may be in one of the following formats:
  526. A string like this: '(\HasChildren) "/" "INBOX"'
  527. Or a tuple like this: ('(\\HasNoChildren) "/" {18}', 'INBOX/contacts')
  528.  
  529. This functions cleans this into a readable name
  530. """
  531. if imap_folder:
  532. if isinstance(imap_folder, tuple):
  533. return imap_folder[1]
  534. result = re.search(
  535. r'(?:\([^\)]*\)\s\")(.)(?:\"\s)(?:\")?([^\"]*)(?:\")?',
  536. imap_folder)
  537. seperator = result.groups()[0]
  538. folder_readable_name = ""
  539. splitname = result.groups()[1].split(seperator) #Not readable now
  540. #If a parent and child exists, format it as parent/child/grandchild
  541. if len(splitname) > 1:
  542. for i in range(0, len(splitname) - 1):
  543. folder_readable_name = splitname[i] + '/'
  544. folder_readable_name = folder_readable_name + splitname[-1]
  545. else:
  546. folder_readable_name = result.groups()[1].split(seperator)[0]
  547. return folder_readable_name
  548. return False
  549.  
  550. def _get_folders(self, cursor, user, context):
  551. """
  552. Get the folders
  553. """
  554. #print account_id
  555. #print context
  556. account_obj = self.pool.get('poweremail.account')
  557. #print account_obj
  558. if context is None:
  559. context = {}
  560. #print context
  561.  
  562. #account_obj = self.pool.get('poweremail.account')
  563.  
  564. if 'active_ids' in context.keys():
  565.  
  566. print 'anupam'
  567. server = account_obj._get_incoming_server(cursor, user, ['actiave_ids'], context)['active_ids'][0]
  568. #print server
  569. folderlist = [ ]
  570. try:
  571. for folders in server.list()[1]:
  572. folder_readable_name = self.make_readable(folders)
  573. if isinstance(folders, tuple):
  574. data = folders[0] + folders[1]
  575. else:
  576. data = folders
  577. if data.find('Noselect') == -1: #If it is a selectable folder
  578. if folder_readable_name:
  579. folderlist.append(
  580. (folder_readable_name,
  581. folder_readable_name)
  582. )
  583. if folder_readable_name == 'INBOX':
  584. self.inboxvalue = folder_readable_name
  585. except Exception, error:
  586. raise osv.except_osv(
  587. _("IMAP Server Folder Error"),
  588. _("An error occurred : %s ") % error)
  589. else:
  590. folderlist = [('invalid', 'Invalid')]
  591. return folderlist
  592.  
  593. _columns = {
  594. 'name':fields.many2one('poweremail.account', string='Email Account',
  595. readonly=True),
  596. 'folder':fields.selection(_get_folders,
  597. string="IMAP Folder"),
  598. # [
  599. # ('inbox', 'Inbox'),
  600. # ('draft', 'Draft'),
  601. # ('sent_item', 'Sent Items')],
  602. # 'IMAP Folder', required = True)
  603.  
  604. }
  605.  
  606. _defaults = {
  607. 'name':lambda self, cursor, user, context: context['active_ids'][0],
  608. #'folder': lambda self, cursor, user, context:self.inboxvalue
  609. }
  610.  
  611. def select_folder(self, cursor, user, account_id, context=None):
  612. """
  613. TODO: Document This
  614. """
  615. print context
  616. print account_id
  617. if self.browse(cursor, user, account_id, context):
  618. if not self.read(cursor, user, account_id,['folder'], context)[0]['folder'] == 'invalid':
  619. self.pool.get(
  620. 'poweremail.account'
  621. ).write(cursor, user, context['active_ids'][0],
  622. {
  623. 'imap_folder': self.read(cursor, user,account_id, ['folder'], context)[0]['folder']
  624.  
  625. })
  626.  
  627. return{
  628. 'type':'ir.actions.act_window_close'
  629. }
  630.  
  631. else:
  632. raise osv.except_osv(
  633. _("Folder Error"),
  634. _("This is an invalid folder"))
  635.  
  636. else:
  637. raise osv.except_osv(
  638. _("Foder Error"),
  639. _("Select a folder before you save record"))
  640.  
  641.  
  642.  
  643. # print context
  644. # account_obj = self.pool.get('poweremail.account')
  645. # print account_obj
  646. # folder_name = self.browse(cursor, user, account_id, context)
  647. # print folder_name
  648. # if not folder_name:
  649. # raise osv.except_osv(
  650. # _("Folder Error"),
  651. # _("Select a folder before you save record "))
  652. # if folder_name == 'invalid':
  653. # raise osv.except_osv(
  654. # _("Folder Error"),
  655. # _("This is an invalid folder "))
  656. # account_obj.write(
  657. # cursor, user, context, account_id,
  658. # {
  659. # 'imap_folder':folder_name
  660. # })
  661. # return {
  662. # 'type':'ir.actions.act_window_close'
  663. # }
  664.  
  665. PoweremailSelectIMAPFolder()
Add Comment
Please, Sign In to add comment