diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py
index 07d0aabe7cd..d37c43bc1ff 100644
--- a/addons/mail/mail_message.py
+++ b/addons/mail/mail_message.py
@@ -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'})
diff --git a/addons/mail/mail_message_view.xml b/addons/mail/mail_message_view.xml
index c3ceb0740fa..83e7474fe1a 100644
--- a/addons/mail/mail_message_view.xml
+++ b/addons/mail/mail_message_view.xml
@@ -36,12 +36,12 @@
-
-
-
+
+
+
@@ -66,7 +66,7 @@
-
+
diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py
index fa613cb219e..6ec9b0247aa 100644
--- a/addons/mail/mail_thread.py
+++ b/addons/mail/mail_thread.py
@@ -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)
diff --git a/addons/mail/scripts/openerp_mailgate/openerp_mailgate.py b/addons/mail/scripts/openerp_mailgate/openerp_mailgate.py
index b75c92d8d34..7e6ba87945f 100755
--- a/addons/mail/scripts/openerp_mailgate/openerp_mailgate.py
+++ b/addons/mail/scripts/openerp_mailgate/openerp_mailgate.py
@@ -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()