[IMP] mail*: mail.message.original: binary field and optional
bzr revid: odo@openerp.com-20110907151348-jiqfqm5cagy8bzto
This commit is contained in:
@@ -26,6 +26,7 @@ import logging
|
||||
import re
|
||||
import time
|
||||
from email.header import decode_header
|
||||
from email.message import Message
|
||||
|
||||
import tools
|
||||
from osv import osv
|
||||
@@ -87,7 +88,6 @@ class mail_message_common(osv.osv_memory):
|
||||
"select plaintext or rich text contents accordingly", readonly=1),
|
||||
'body_text': fields.text('Text contents', help="Plain-text version of the message"),
|
||||
'body_html': fields.text('Rich-text contents', help="Rich-text/HTML version of the message"),
|
||||
'original': fields.text('Original', help="Original version of the message, as it was sent on the network", readonly=1),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
@@ -175,6 +175,7 @@ class mail_message(osv.osv):
|
||||
('cancel', 'Cancelled'),
|
||||
], 'State', readonly=True),
|
||||
'auto_delete': fields.boolean('Auto Delete', help="Permanently delete this email after sending it"),
|
||||
'original': fields.binary('Original', help="Original version of the message, as it was sent on the network", readonly=1),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
@@ -307,13 +308,16 @@ class mail_message(osv.osv):
|
||||
_logger.exception("Failed processing mail queue")
|
||||
return res
|
||||
|
||||
def parse_message(self, message):
|
||||
def parse_message(self, message, save_original=False):
|
||||
"""Parses a string or email.message.Message representing an
|
||||
RFC-2822 email, and returns a generic dict holding the
|
||||
message details.
|
||||
|
||||
:param message: the message to parse
|
||||
:type message: email.message.Message | string | unicode
|
||||
:param bool save_original: whether the returned dict
|
||||
should include an ``original`` entry with the base64
|
||||
encoded source of the message.
|
||||
:rtype: dict
|
||||
:return: A dict with the following structure, where each
|
||||
field may not be present if missing in original
|
||||
@@ -349,8 +353,11 @@ class mail_message(osv.osv):
|
||||
message_id = msg_txt.get('message-id', False)
|
||||
msg = {}
|
||||
|
||||
# save original, we need to be able to read the original email sometimes
|
||||
msg['original'] = message
|
||||
if save_original:
|
||||
# save original, we need to be able to read the original email sometimes
|
||||
msg['original'] = message.as_string() if isinstance(message, Message) \
|
||||
else message
|
||||
msg['original'] = base64.b64encode(msg['original']) # binary fields are b64
|
||||
|
||||
if not message_id:
|
||||
# Very unusual situation, be we should be fault-tolerant here
|
||||
@@ -487,8 +494,7 @@ class mail_message(osv.osv):
|
||||
mail_server_id=message.mail_server_id.id,
|
||||
context=context)
|
||||
if res:
|
||||
message.write({'state':'sent', 'message_id': res,
|
||||
'original': msg.as_string(message.email_from)})
|
||||
message.write({'state':'sent', 'message_id': res})
|
||||
else:
|
||||
message.write({'state':'exception'})
|
||||
|
||||
|
||||
@@ -36,12 +36,12 @@
|
||||
</group>
|
||||
|
||||
<notebook colspan="4">
|
||||
<page string="Body (Plain)" attrs="{'invisible':[('subtype','=','html')]}">
|
||||
<field name="body_text" colspan="4" widget="text" nolabel="1"/>
|
||||
</page>
|
||||
<page string="Body (Rich)" attrs="{'invisible':[('subtype','=','plain')]}">
|
||||
<field name="body_html" widget="text_html" nolabel="1" colspan="4"/>
|
||||
</page>
|
||||
<page string="Body (Plain)">
|
||||
<field name="body_text" colspan="4" widget="text" nolabel="1"/>
|
||||
</page>
|
||||
</notebook>
|
||||
|
||||
<separator string="" colspan="4"/>
|
||||
@@ -66,7 +66,7 @@
|
||||
<field name="subtype" attrs="{'invisible':[('subtype', '=', False)]}"/>
|
||||
<field name="auto_delete"/>
|
||||
<field name="headers" colspan="4" attrs="{'invisible':[('headers', '=', False)]}"/>
|
||||
<field name="original" colspan="4" height="350" attrs="{'invisible':[('original', '=', False)]}"/>
|
||||
<field name="original" colspan="4" attrs="{'invisible':[('original', '=', False)]}"/>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
|
||||
@@ -153,10 +153,14 @@ class mail_thread(osv.osv):
|
||||
containing all the details passed as parameters. All attachments
|
||||
will be attached to the thread record as well as to the actual
|
||||
message.
|
||||
If only the ``threads`` and ``subject`` parameters are provided,
|
||||
a *event log* message is created, without the usual envelope
|
||||
attributes (sender, recipients, etc.).
|
||||
|
||||
:param threads: list of thread ids, or list of browse_records representing
|
||||
threads to which a new message should be attached
|
||||
:param subject: Thread action keyword e.g.: If thread is closed "Close" keyword is used
|
||||
:param subject: subject of the message, or description of the event if this
|
||||
is an *event log* entry.
|
||||
:param email_to: Email-To / Recipient address
|
||||
:param email_from: Email From / Sender address if any
|
||||
:param email_cc: Comma-Separated list of Carbon Copy Emails To addresse if any
|
||||
@@ -291,7 +295,8 @@ class mail_thread(osv.osv):
|
||||
context = context)
|
||||
|
||||
|
||||
def message_process(self, cr, uid, model, message, custom_values=None, context=None):
|
||||
def message_process(self, cr, uid, model, message, custom_values=None,
|
||||
save_original=False, context=None):
|
||||
"""Process an incoming RFC2822 email message related to the
|
||||
given thread model, relying on ``mail.message.parse()``
|
||||
for the parsing operation, and then calling ``message_new``
|
||||
@@ -307,6 +312,8 @@ class mail_thread(osv.osv):
|
||||
to pass to ``message_new`` if a new
|
||||
record needs to be created. Ignored
|
||||
if the thread record already exists.
|
||||
:param bool save_original: whether to keep a copy of the original
|
||||
email source attached to the message after it is imported.
|
||||
"""
|
||||
# extract message bytes - we are forced to pass the message as binary because
|
||||
# we don't know its encoding until we parse its headers and hence can't
|
||||
@@ -328,7 +335,7 @@ class mail_thread(osv.osv):
|
||||
if isinstance(message, unicode):
|
||||
message = message.encode('utf-8')
|
||||
msg_txt = email.message_from_string(message)
|
||||
msg = mail_message.parse_message(msg_txt)
|
||||
msg = mail_message.parse_message(msg_txt, save_original=save_original)
|
||||
|
||||
# Create New Record into particular model
|
||||
def create_record(msg):
|
||||
@@ -357,6 +364,9 @@ class mail_thread(osv.osv):
|
||||
if model_pool.exists(cr, uid, res_id):
|
||||
if hasattr(model_pool, 'message_update'):
|
||||
model_pool.message_update(cr, uid, [res_id], msg, {}, context=context)
|
||||
else:
|
||||
# referenced thread was not found, we'll have to create a new one
|
||||
res_id = False
|
||||
if not res_id:
|
||||
res_id = create_record(msg)
|
||||
#To forward the email to other followers
|
||||
@@ -386,8 +396,8 @@ class mail_thread(osv.osv):
|
||||
followers = model_pool.message_thread_followers(cr, uid, [res.id])[res.id]
|
||||
else:
|
||||
followers = self.message_thread_followers(cr, uid, [res.id])[res.id]
|
||||
message_followers_emails = mail_message.to_email(','.join(filter(None, followers)))
|
||||
message_recipients = mail_message.to_email(','.join(filter(None,
|
||||
message_followers_emails = to_email(','.join(filter(None, followers)))
|
||||
message_recipients = to_email(','.join(filter(None,
|
||||
[decode(msg['from']),
|
||||
decode(msg['to']),
|
||||
decode(msg['cc'])])))
|
||||
@@ -398,7 +408,7 @@ class mail_thread(osv.osv):
|
||||
del msg['reply-to']
|
||||
msg['reply-to'] = res.section_id.reply_to
|
||||
|
||||
smtp_from = mail_message.to_email(msg['from'])
|
||||
smtp_from = to_email(msg['from'])
|
||||
msg['from'] = smtp_from
|
||||
msg['to'] = forward_to
|
||||
msg['message-id'] = tools.generate_tracking_message_id(res.id)
|
||||
|
||||
@@ -46,13 +46,14 @@ class DefaultConfig(object):
|
||||
OPENERP_PORT = 8069
|
||||
OPENERP_DEFAULT_DATABASE = 'openerp'
|
||||
MAIL_ERROR = 'error@example.com'
|
||||
MAIL_SERVER = 'localhost'
|
||||
MAIL_ADMINS = ('admin@example.com',)
|
||||
MAIL_SERVER = 'smtp.example.com'
|
||||
MAIL_SERVER_PORT = 25
|
||||
MAIL_ADMINS = ('info@example.com',)
|
||||
|
||||
config = DefaultConfig()
|
||||
|
||||
|
||||
def send_mail(_from_, to_, subject, text, files=None, server=config.MAIL_SERVER):
|
||||
def send_mail(_from_, to_, subject, text, files=None, server=config.MAIL_SERVER, port=config.MAIL_SERVER_PORT):
|
||||
assert isinstance(to_, (list, tuple))
|
||||
|
||||
if files is None:
|
||||
@@ -74,7 +75,7 @@ def send_mail(_from_, to_, subject, text, files=None, server=config.MAIL_SERVER)
|
||||
% file_name)
|
||||
msg.attach(part)
|
||||
|
||||
smtp = smtplib.SMTP(server)
|
||||
smtp = smtplib.SMTP(server, port=port)
|
||||
smtp.sendmail(_from_, to_, msg.as_string() )
|
||||
smtp.close()
|
||||
|
||||
@@ -104,16 +105,15 @@ class EmailParser(object):
|
||||
self.email_default = email_default
|
||||
|
||||
|
||||
def parse(self, message, custom_values=None):
|
||||
if custom_values is None:
|
||||
custom_values = {}
|
||||
def parse(self, message, custom_values=None, save_original=None):
|
||||
# pass message as bytes because we don't know its encoding until we parse its headers
|
||||
# and hence can't convert it to utf-8 for transport
|
||||
res_id = self.rpc('mail.thread',
|
||||
'message_process',
|
||||
self.model,
|
||||
xmlrpclib.Binary(message),
|
||||
custom_values)
|
||||
custom_values or {},
|
||||
save_original or False)
|
||||
|
||||
def configure_parser():
|
||||
parser = optparse.OptionParser(usage='usage: %prog [options]', version='%prog v1.1')
|
||||
@@ -145,6 +145,10 @@ def configure_parser():
|
||||
parser.add_option("--custom-values", dest="custom_values",
|
||||
help="Add Custom Values to the object",
|
||||
default=None)
|
||||
parser.add_option("-s", dest="save_original",
|
||||
action="store_true",
|
||||
help="Attach a copy of original email to the message entry",
|
||||
default=False)
|
||||
|
||||
return parser
|
||||
|
||||
@@ -169,12 +173,14 @@ def main():
|
||||
|
||||
custom_values = {}
|
||||
try:
|
||||
print "custom vals: %s" % options.custom_values
|
||||
custom_values = dict(eval(options.custom_values or {} ))
|
||||
except:
|
||||
pass
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
try:
|
||||
email_parser.parse(msg_txt, custom_values)
|
||||
email_parser.parse(msg_txt, custom_values, options.save_original or False)
|
||||
except Exception:
|
||||
msg = '\n'.join([
|
||||
'parameters',
|
||||
@@ -191,6 +197,7 @@ def main():
|
||||
config.MAIL_ADMINS,
|
||||
subject, msg, files=[('message.txt', msg_txt)]
|
||||
)
|
||||
sys.stderr.write("Failed to deliver email to OpenERP Server, sending error notification to %s\n" % config.MAIL_ADMINS)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user