[FIX] email_template: email_template.preview.fields_view_get() is broken
[odoo/odoo.git] / addons / email_template / email_template.py
index 37b3877..1189e1c 100644 (file)
@@ -1,8 +1,29 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2009 Sharoon Thomas
+#    Copyright (C) 2010-2010 OpenERP SA (<http://www.openerp.com>)
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>
+#
+##############################################################################
+
 import base64
 import random
-import time
-import types
 import netsvc
+import re
 
 LOGGER = netsvc.Logger()
 
@@ -10,10 +31,9 @@ TEMPLATE_ENGINES = []
 
 from osv import osv, fields
 from tools.translate import _
-from mako.template import Template  #For backward combatibility
+
 try:
     from mako.template import Template as MakoTemplate
-    from mako import exceptions
     TEMPLATE_ENGINES.append(('mako', 'Mako Templates'))
 except:
     LOGGER.notifyChannel(
@@ -36,11 +56,9 @@ except:
          _("Django templates not installed")
     )
 
-import email_template_engines
 import tools
-import report
 import pooler
-
+import logging
 
 def get_value(cursor, user, recid, message=None, template=None, context=None):
     """
@@ -50,7 +68,7 @@ def get_value(cursor, user, recid, message=None, template=None, context=None):
     @param recid: ID of the target record under evaluation
     @param message: The expression to be evaluated
     @param template: BrowseRecord object of the current template
-    @param context: Open ERP Context
+    @param context: OpenERP Context
     @return: Computed message (unicode) or u""
     """
     pool = pooler.get_pool(cursor.dbname)
@@ -78,13 +96,14 @@ def get_value(cursor, user, recid, message=None, template=None, context=None):
                 reply = templ.render(Context(env))
             return reply or False
         except Exception:
+            logging.exception("can't render %r", message)
             return u""
     else:
         return message
 
 class email_template(osv.osv):
     "Templates for sending Email"
-    
+
     _name = "email.template"
     _description = 'Email Templates for Models'
 
@@ -103,29 +122,44 @@ class email_template(osv.osv):
 
     _columns = {
         'name' : fields.char('Name', size=100, required=True),
-        'object_name':fields.many2one('ir.model', 'Model'),
+        'object_name':fields.many2one('ir.model', 'Resource'),
         'model_int_name':fields.char('Model Internal Name', size=200,),
-        'enforce_from_account':fields.many2one(
+        'from_account':fields.many2one(
                    'email_template.account',
-                   string="Enforce From Account",
-                   help="Emails will be sent only from this account."),
-        'from_email' : fields.related('enforce_from_account', 'email_id',
-                                                type='char', string='From',),        
+                   string="Email Account",
+                   help="Emails will be sent from this approved account."),
         'def_to':fields.char(
-                 'Recepient (To)',
+                 'Recipient (To)',
                  size=250,
-                 help="The default recepient of email." 
-                 "Placeholders can be used here."),
+                 help="The Recipient of email. "
+                 "Placeholders can be used here. "
+                 "e.g. ${object.email_to}"),
         'def_cc':fields.char(
-                 'Default CC',
+                 'CC',
                  size=250,
-                 help="The default CC for the email."
-                 " Placeholders can be used here."),
+                 help="Carbon Copy address(es), comma-separated."
+                    " Placeholders can be used here. "
+                    "e.g. ${object.email_cc}"),
         'def_bcc':fields.char(
-                  'Default BCC',
+                  'BCC',
                   size=250,
-                  help="The default BCC for the email."
-                  " Placeholders can be used here."),
+                  help="Blind Carbon Copy address(es), comma-separated."
+                    " Placeholders can be used here. "
+                    "e.g. ${object.email_bcc}"),
+        'reply_to':fields.char('Reply-To',
+                    size=250,
+                    help="The address recipients should reply to,"
+                    " if different from the From address."
+                    " Placeholders can be used here. "
+                    "e.g. ${object.email_reply_to}"),
+        'message_id':fields.char('Message-ID',
+                    size=250,
+                    help="Specify the Message-ID SMTP header to use in outgoing emails. Please note that this overrides the Resource tracking option! Placeholders can be used here."),
+        'track_campaign_item':fields.boolean('Resource Tracking',
+                                help="Enable this is you wish to include a special \
+tracking marker in outgoing emails so you can identify replies and link \
+them back to the corresponding resource record. \
+This is useful for CRM leads for example"),
         'lang':fields.char(
                    'Language',
                    size=250,
@@ -133,9 +167,9 @@ class email_template(osv.osv):
                    " Placeholders can be used here. "
                    "eg. ${object.partner_id.lang}"),
         'def_subject':fields.char(
-                  'Default Subject',
+                  'Subject',
                   size=200,
-                  help="The default subject of email."
+                  help="The subject of email."
                   " Placeholders can be used here.",
                   translate=True),
         'def_body_text':fields.text(
@@ -148,24 +182,33 @@ class email_template(osv.osv):
                     translate=True),
         'use_sign':fields.boolean(
                   'Signature',
-                  help="the signature from the User details" 
-                  "will be appened to the mail"),
+                  help="the signature from the User details"
+                  " will be appended to the mail"),
         'file_name':fields.char(
-                'File Name Pattern',
+                'Report Filename',
                 size=200,
-                help="File name pattern can be specified with placeholders." 
-                "eg. 2009_SO003.pdf",
+                help="Name of the generated report file. Placeholders can be used in the filename. eg: 2009_SO003.pdf",
                 translate=True),
         'report_template':fields.many2one(
                   'ir.actions.report.xml',
                   'Report to send'),
+        'attachment_ids': fields.many2many(
+                    'ir.attachment',
+                    'email_template_attachment_rel',
+                    'email_template_id',
+                    'attachment_id',
+                    'Attached Files',
+                    help="You may attach existing files to this template, "
+                         "so they will be added in all emails created from this template"),
         'ref_ir_act_window':fields.many2one(
                     'ir.actions.act_window',
                     'Window Action',
+                    help="Action that will open this email template on Resource records",
                     readonly=True),
         'ref_ir_value':fields.many2one(
                    'ir.values',
                    'Wizard Button',
+                   help="Button in the side bar of the form view of this Resource that will invoke the Window Action",
                    readonly=True),
         'allowed_groups':fields.many2many(
                   'res.groups',
@@ -222,41 +265,42 @@ class email_template(osv.osv):
         'template_language' : lambda *a:'mako',
 
     }
+
     _sql_constraints = [
         ('name', 'unique (name)', _('The template name must be unique !'))
     ]
 
-    def create(self, cr, uid, vals, context=None):
-        id = super(email_template, self).create(cr, uid, vals, context)
-        src_obj = self.pool.get('ir.model').read(cr, uid, vals['object_name'], ['model'], context)['model']
+    def create_action(self, cr, uid, ids, context):
+        vals = {}
+        template_obj = self.browse(cr, uid, ids)[0]
+        src_obj = template_obj.object_name.model
         vals['ref_ir_act_window'] = self.pool.get('ir.actions.act_window').create(cr, uid, {
-             'name': _("%s Mail Form") % vals['name'],
+             'name': template_obj.name,
              'type': 'ir.actions.act_window',
              'res_model': 'email_template.send.wizard',
              'src_model': src_obj,
              'view_type': 'form',
-             'context': "{'src_model':'%s','template_id':'%d','src_rec_id':active_id,'src_rec_ids':active_ids}" % (src_obj, id),
+             'context': "{'src_model':'%s','template_id':'%d','src_rec_id':active_id,'src_rec_ids':active_ids}" % (src_obj, template_obj.id),
              'view_mode':'form,tree',
              'view_id': self.pool.get('ir.ui.view').search(cr, uid, [('name', '=', 'email_template.send.wizard.form')], context=context)[0],
              'target': 'new',
              'auto_refresh':1
         }, context)
         vals['ref_ir_value'] = self.pool.get('ir.values').create(cr, uid, {
-             'name': _('Send Mail (%s)') % vals['name'],
+             'name': _('Send Mail (%s)') % template_obj.name,
              'model': src_obj,
              'key2': 'client_action_multi',
              'value': "ir.actions.act_window," + str(vals['ref_ir_act_window']),
              'object': True,
          }, context)
-        self.write(cr, uid, id, {
+        self.write(cr, uid, ids, {
             'ref_ir_act_window': vals['ref_ir_act_window'],
             'ref_ir_value': vals['ref_ir_value'],
         }, context)
-        return id
+        return True
 
-    def unlink(self, cr, uid, ids, context=None):
+    def unlink_action(self, cr, uid, ids, context):
         for template in self.browse(cr, uid, ids, context):
-            obj = self.pool.get(template.object_name.model)
             try:
                 if template.ref_ir_act_window:
                     self.pool.get('ir.actions.act_window').unlink(cr, uid, template.ref_ir_act_window.id, context)
@@ -264,8 +308,15 @@ class email_template(osv.osv):
                     self.pool.get('ir.values').unlink(cr, uid, template.ref_ir_value.id, context)
             except:
                 raise osv.except_osv(_("Warning"), _("Deletion of Record failed"))
+
+    def delete_action(self, cr, uid, ids, context):
+        self.unlink_action(cr, uid, ids, context)
+        return True
+
+    def unlink(self, cr, uid, ids, context=None):
+        self.unlink_action(cr, uid, ids, context)
         return super(email_template, self).unlink(cr, uid, ids, context)
-    
+
     def copy(self, cr, uid, id, default=None, context=None):
         if default is None:
             default = {}
@@ -277,40 +328,36 @@ class email_template(osv.osv):
             new_name = new_name + '_' + random.choice('abcdefghij') + random.choice('lmnopqrs') + random.choice('tuvwzyz')
         default.update({'name':new_name})
         return super(email_template, self).copy(cr, uid, id, default, context)
-    
-    def compute_pl(self,
-                   model_object_field,
-                   sub_model_object_field,
-                   null_value, template_language='mako'):
+
+    def build_expression(self, field_name, sub_field_name, null_value, template_language='mako'):
         """
-        Returns the expression based on data provided
-        @param model_object_field: First level field
-        @param sub_model_object_field: Second level drilled down field (M2O)
-        @param null_value: What has to be returned if the value is empty
-        @param template_language: The language used for templating
+        Returns a template expression based on data provided
+        @param field_name: field name
+        @param sub_field_name: sub field name (M2O)
+        @param null_value: default value if the target value is empty
+        @param template_language: name of template engine
         @return: computed expression
         """
-        #Configure for MAKO
-        copy_val = ''
+
+        expression = ''
         if template_language == 'mako':
-            if model_object_field:
-                copy_val = "${object." + model_object_field
-            if sub_model_object_field:
-                copy_val += "." + sub_model_object_field
-            if null_value:
-                copy_val += " or '" + null_value + "'"
-            if model_object_field:
-                copy_val += "}"
+            if field_name:
+                expression = "${object." + field_name
+                if sub_field_name:
+                    expression += "." + sub_field_name
+                if null_value:
+                    expression += " or '''%s'''" % null_value
+                expression += "}"
         elif template_language == 'django':
-            if model_object_field:
-                copy_val = "{{object." + model_object_field
-            if sub_model_object_field:
-                copy_val += "." + sub_model_object_field
-            if null_value:
-                copy_val = copy_val + '|default:"' + null_value + '"'  
-            copy_val = copy_val + "}}"        
-        return copy_val 
-            
+            if field_name:
+                expression = "{{object." + field_name
+                if sub_field_name:
+                    expression += "." + sub_field_name
+                if null_value:
+                    expression += "|default: '''%s'''" % null_value
+                expression += "}}"
+        return expression
+
     def onchange_model_object_field(self, cr, uid, ids, model_object_field, template_language, context=None):
         if not model_object_field:
             return {}
@@ -321,7 +368,7 @@ class email_template(osv.osv):
             res_ids = self.pool.get('ir.model').search(cr, uid, [('model', '=', field_obj.relation)], context=context)
             if res_ids:
                 result['sub_object'] = res_ids[0]
-                result['copyvalue'] = self.compute_pl(False,
+                result['copyvalue'] = self.build_expression(False,
                                                       False,
                                                       False,
                                                       template_language)
@@ -330,7 +377,7 @@ class email_template(osv.osv):
         else:
             #Its a simple field... just compute placeholder
             result['sub_object'] = False
-            result['copyvalue'] = self.compute_pl(field_obj.name,
+            result['copyvalue'] = self.build_expression(field_obj.name,
                                                   False,
                                                   False,
                                                   template_language
@@ -338,7 +385,7 @@ class email_template(osv.osv):
             result['sub_model_object_field'] = False
             result['null_value'] = False
         return {'value':result}
-        
+
     def onchange_sub_model_object_field(self, cr, uid, ids, model_object_field, sub_model_object_field, template_language, context=None):
         if not model_object_field or not sub_model_object_field:
             return {}
@@ -349,7 +396,7 @@ class email_template(osv.osv):
             sub_field_obj = self.pool.get('ir.model.fields').browse(cr, uid, sub_model_object_field, context)
             if res_ids:
                 result['sub_object'] = res_ids[0]
-                result['copyvalue'] = self.compute_pl(field_obj.name,
+                result['copyvalue'] = self.build_expression(field_obj.name,
                                                       sub_field_obj.name,
                                                       False,
                                                       template_language
@@ -359,7 +406,7 @@ class email_template(osv.osv):
         else:
             #Its a simple field... just compute placeholder
             result['sub_object'] = False
-            result['copyvalue'] = self.compute_pl(field_obj.name,
+            result['copyvalue'] = self.build_expression(field_obj.name,
                                                   False,
                                                   False,
                                                   template_language
@@ -378,7 +425,7 @@ class email_template(osv.osv):
             sub_field_obj = self.pool.get('ir.model.fields').browse(cr, uid, sub_model_object_field, context)
             if res_ids:
                 result['sub_object'] = res_ids[0]
-                result['copyvalue'] = self.compute_pl(field_obj.name,
+                result['copyvalue'] = self.build_expression(field_obj.name,
                                                       sub_field_obj.name,
                                                       null_value,
                                                       template_language
@@ -388,7 +435,7 @@ class email_template(osv.osv):
         else:
             #Its a simple field... just compute placeholder
             result['sub_object'] = False
-            result['copyvalue'] = self.compute_pl(field_obj.name,
+            result['copyvalue'] = self.build_expression(field_obj.name,
                                                   False,
                                                   null_value,
                                                   template_language
@@ -396,7 +443,37 @@ class email_template(osv.osv):
             result['sub_model_object_field'] = False
             result['null_value'] = null_value
         return {'value':result}
-               
+
+    def _add_attachment(self, cursor, user, mailbox_id, name, data, filename, context=None):
+        """
+        Add an attachment to a given mailbox entry.
+
+        :param data: base64 encoded attachment data to store
+        """
+        attachment_obj = self.pool.get('ir.attachment')
+        attachment_data = {
+            'name':  (name or '') + _(' (Email Attachment)'),
+            'datas': data,
+            'datas_fname': filename,
+            'description': name or _('No Description'),
+            'res_model':'email_template.mailbox',
+            'res_id': mailbox_id,
+        }
+        attachment_id = attachment_obj.create(cursor,
+                                              user,
+                                              attachment_data,
+                                              context)
+        if attachment_id:
+            self.pool.get('email_template.mailbox').write(
+                              cursor,
+                              user,
+                              mailbox_id,
+                              {
+                               'attachments_ids':[(4, attachment_id)],
+                               'mail_type':'multipart/mixed'
+                              },
+                              context)
+
     def generate_attach_reports(self,
                                  cursor,
                                  user,
@@ -406,8 +483,8 @@ class email_template(osv.osv):
                                  context=None):
         """
         Generate report to be attached and attach it
-        to the email
-        
+        to the email, and add any directly attached files as well.
+
         @param cursor: Database Cursor
         @param user: ID of User
         @param template: Browse record of
@@ -415,59 +492,39 @@ class email_template(osv.osv):
         @param record_id: ID of the target model
                           for which this mail has
                           to be generated
-        @param mail: Browse record of email object 
-        @return: True 
+        @param mail: Browse record of email object
+        @return: True
         """
-        reportname = 'report.' + \
-            self.pool.get('ir.actions.report.xml').read(
-                                         cursor,
-                                         user,
-                                         template.report_template.id,
-                                         ['report_name'],
-                                         context)['report_name']
-        service = netsvc.LocalService(reportname)
-        data = {}
-        data['model'] = template.model_int_name
-        (result, format) = service.create(cursor,
-                                          user,
-                                          [record_id],
-                                          data,
-                                          context)
-        attachment_obj = self.pool.get('ir.attachment')
-        new_att_vals = {
-            'name':mail.subject + ' (Email Attachment)',
-            'datas':base64.b64encode(result),
-            'datas_fname':tools.ustr(
-                             get_value(
-                                   cursor,
-                                   user,
-                                   record_id,
-                                   template.file_name,
-                                   template,
-                                   context
-                                   ) or 'Report') + "." + format,
-            'description':mail.subject or "No Description",
-            'res_model':'email_template.mailbox',
-            'res_id':mail.id
-        }
-        attachment_id = attachment_obj.create(cursor,
+        if template.report_template:
+            reportname = 'report.' + \
+                self.pool.get('ir.actions.report.xml').read(
+                                             cursor,
+                                             user,
+                                             template.report_template.id,
+                                             ['report_name'],
+                                             context)['report_name']
+            service = netsvc.LocalService(reportname)
+            data = {}
+            data['model'] = template.model_int_name
+            (result, format) = service.create(cursor,
                                               user,
-                                              new_att_vals,
+                                              [record_id],
+                                              data,
                                               context)
-        if attachment_id:
-            self.pool.get('email_template.mailbox').write(
-                              cursor,
-                              user,
-                              mail.id,
-                              {
-                               'attachments_ids':[
-                                                  [6, 0, [attachment_id]]
-                                                    ],
-                               'mail_type':'multipart/mixed'
-                               },
-                               context)
+            fname = tools.ustr(get_value(cursor, user, record_id,
+                                         template.file_name, template, context)
+                               or 'Report')
+            ext = '.' + format
+            if not fname.endswith(ext):
+                fname += ext
+            self._add_attachment(cursor, user, mail.id, mail.subject, base64.b64encode(result), fname, context)
+
+        if template.attachment_ids:
+            for attachment in template.attachment_ids:
+                self._add_attachment(cursor, user, mail.id, attachment.name, attachment.datas, attachment.datas_fname, context)
+
         return True
-    
+
     def _generate_mailbox_item_from_template(self,
                                       cursor,
                                       user,
@@ -477,7 +534,7 @@ class email_template(osv.osv):
         """
         Generates an email from the template for
         record record_id of target object
-        
+
         @param cursor: Database Cursor
         @param user: ID of User
         @param template: Browse record of
@@ -485,7 +542,7 @@ class email_template(osv.osv):
         @param record_id: ID of the target model
                           for which this mail has
                           to be generated
-        @return: ID of created object 
+        @return: ID of created object
         """
         if context is None:
             context = {}
@@ -500,9 +557,9 @@ class email_template(osv.osv):
                                                     )
         else:
             from_account = {
-                            'id':template.enforce_from_account.id,
-                            'name':template.enforce_from_account.name,
-                            'email_id':template.enforce_from_account.email_id
+                            'id':template.from_account.id,
+                            'name':template.from_account.name,
+                            'email_id':template.from_account.email_id
                             }
         lang = get_value(cursor,
                          user,
@@ -513,10 +570,22 @@ class email_template(osv.osv):
         if lang:
             ctx = context.copy()
             ctx.update({'lang':lang})
-            template = self.browse(cursor, user, template_id, context=ctx)
+            template = self.browse(cursor, user, template.id, context=ctx)
+
+        # determine name of sender, either it is specified in email_id or we
+        # use the account name
+        email_id = from_account['email_id'].strip()
+        email_from = re.findall(r'([^ ,<@]+@[^> ,]+)', email_id)[0]
+        if email_from != email_id:
+            # we should keep it all, name is probably specified in the address
+            email_from = from_account['email_id']
+        else:
+            email_from = tools.ustr(from_account['name']) + "<" + tools.ustr('email_id') + ">",
+
+        # FIXME: should do this in a loop and rename template fields to the corresponding
+        # mailbox fields. (makes no sense to have different names I think.
         mailbox_values = {
-            'email_from': tools.ustr(from_account['name']) + \
-                        "<" + tools.ustr(from_account['email_id']) + ">",
+            'email_from': email_from,
             'email_to':get_value(cursor,
                                user,
                                record_id,
@@ -535,6 +604,12 @@ class email_template(osv.osv):
                                 template.def_bcc,
                                 template,
                                 context),
+            'reply_to':get_value(cursor,
+                                user,
+                                record_id,
+                                template.reply_to,
+                                template,
+                                context),
             'subject':get_value(cursor,
                                     user,
                                     record_id,
@@ -557,8 +632,17 @@ class email_template(osv.osv):
             #This is a mandatory field when automatic emails are sent
             'state':'na',
             'folder':'drafts',
-            'mail_type':'multipart/alternative' 
+            'mail_type':'multipart/alternative',
         }
+
+        if template['message_id']:
+            # use provided message_id with placeholders
+            mailbox_values.update({'message_id': get_value(cursor, user, record_id, template['message_id'], template, context)})
+
+        elif template['track_campaign_item']:
+            # get appropriate message-id
+            mailbox_values.update({'message_id': tools.misc.generate_tracking_message_id(record_id)})
+
         if not mailbox_values['account_id']:
             raise Exception("Unable to send the mail. No account linked to the template.")
         #Use signatures if allowed
@@ -572,17 +656,15 @@ class email_template(osv.osv):
                 mailbox_values['body_text'] += sign
             if mailbox_values['body_html']:
                 mailbox_values['body_html'] += sign
-        print 'Creating', mailbox_values
         mailbox_id = self.pool.get('email_template.mailbox').create(
                                                              cursor,
                                                              user,
                                                              mailbox_values,
                                                              context)
 
-        print 'Sending', mailbox_id
-        self.pool.get('email_template.mailbox').send_this_mail(cursor, user, [mailbox_id], context)
         return mailbox_id
 
+
     def generate_mail(self,
                       cursor,
                       user,
@@ -594,7 +676,8 @@ class email_template(osv.osv):
         template = self.browse(cursor, user, template_id, context=context)
         if not template:
             raise Exception("The requested template could not be loaded")
-        print 'loaded', record_ids
+        result = True
+        mailbox_obj = self.pool.get('email_template.mailbox')
         for record_id in record_ids:
             mailbox_id = self._generate_mailbox_item_from_template(
                                                                 cursor,
@@ -602,15 +685,14 @@ class email_template(osv.osv):
                                                                 template,
                                                                 record_id,
                                                                 context)
-            print 'loaded'
-            mail = self.pool.get('email_template.mailbox').browse(
-                                                        cursor,
-                                                        user,
-                                                        mailbox_id,
-                                                        context=context
-                                                              )
-            if template.report_template:
-                self._generate_attach_reports(
+            mail = mailbox_obj.browse(
+                                        cursor,
+                                        user,
+                                        mailbox_id,
+                                        context=context
+                                              )
+            if template.report_template or template.attachment_ids:
+                self.generate_attach_reports(
                                               cursor,
                                               user,
                                               template,
@@ -618,6 +700,7 @@ class email_template(osv.osv):
                                               mail,
                                               context
                                               )
+
             self.pool.get('email_template.mailbox').write(
                                                 cursor,
                                                 user,
@@ -625,32 +708,54 @@ class email_template(osv.osv):
                                                 {'folder':'outbox'},
                                                 context=context
             )
-        return True
+            # TODO : manage return value of all the records
+            result = self.pool.get('email_template.mailbox').send_this_mail(cursor, user, [mailbox_id], context)
+        return result
 
 email_template()
 
+
+## FIXME: this class duplicates a lot of features of the email template send wizard,
+##        one of the 2 should inherit from the other!
+
 class email_template_preview(osv.osv_memory):
     _name = "email_template.preview"
     _description = "Email Template Preview"
-    
+
     def _get_model_recs(self, cr, uid, context=None):
         if context is None:
             context = {}
             #Fills up the selection box which allows records from the selected object to be displayed
         self.context = context
-        if 'template_id' in context.keys():
+        if 'template_id' in context:
             ref_obj_id = self.pool.get('email.template').read(cr, uid, context['template_id'], ['object_name'], context)
             ref_obj_name = self.pool.get('ir.model').read(cr, uid, ref_obj_id['object_name'][0], ['model'], context)['model']
-            ref_obj_ids = self.pool.get(ref_obj_name).search(cr, uid, [], context=context)
-            ref_obj_recs = self.pool.get(ref_obj_name).name_get(cr, uid, ref_obj_ids, context)
-            return ref_obj_recs    
-        
+            model_obj = self.pool.get(ref_obj_name)
+            ref_obj_ids = model_obj.search(cr, uid, [], 0, 20, 'id desc', context=context)
+
+            # also add the default one if requested, otherwise it won't be available for selection:
+            default_id = context.get('default_rel_model_ref')
+            if default_id and default_id not in ref_obj_ids:
+                ref_obj_ids.insert(0, default_id)
+            return model_obj.name_get(cr, uid, ref_obj_ids, context)
+        return []
+
+    def default_get(self, cr, uid, fields, context=None):
+        if context is None:
+            context = {}
+        result = super(email_template_preview, self).default_get(cr, uid, fields, context=context)
+        if (not fields or 'rel_model_ref' in fields) and 'template_id' in context \
+           and not result.get('rel_model_ref'):
+            selectables = self._get_model_recs(cr, uid, context=context)
+            result['rel_model_ref'] = selectables and selectables[0][0] or False
+        return result
+
     def _default_model(self, cursor, user, context=None):
         """
         Returns the default value for model field
         @param cursor: Database Cursor
         @param user: ID of current user
-        @param context: Open ERP Context
+        @param context: OpenERP Context
         """
         return self.pool.get('email.template').read(
                                                    cursor,
@@ -658,7 +763,7 @@ class email_template_preview(osv.osv_memory):
                                                    context['template_id'],
                                                    ['object_name'],
                                                    context)['object_name']
-        
+
     _columns = {
         'ref_template':fields.many2one(
                                        'email.template',
@@ -668,6 +773,16 @@ class email_template_preview(osv.osv_memory):
         'to':fields.char('To', size=250, readonly=True),
         'cc':fields.char('CC', size=250, readonly=True),
         'bcc':fields.char('BCC', size=250, readonly=True),
+        'reply_to':fields.char('Reply-To',
+                    size=250,
+                    help="The address recipients should reply to,"
+                         " if different from the From address."
+                         " Placeholders can be used here."),
+        'message_id':fields.char('Message-ID',
+                    size=250,
+                    help="The Message-ID header value, if you need to"
+                         "specify it, for example to automatically recognize the replies later."
+                        " Placeholders can be used here."),
         'subject':fields.char('Subject', size=200, readonly=True),
         'body_text':fields.text('Body', readonly=True),
         'body_html':fields.text('Body', readonly=True),
@@ -675,7 +790,7 @@ class email_template_preview(osv.osv_memory):
     }
     _defaults = {
         'ref_template': lambda self, cr, uid, ctx:ctx['template_id'],
-        'rel_model': _default_model
+        'rel_model': _default_model,
     }
     def on_change_ref(self, cr, uid, ids, rel_model_ref, context=None):
         if context is None:
@@ -695,12 +810,17 @@ class email_template_preview(osv.osv_memory):
         vals['to'] = get_value(cr, uid, rel_model_ref, template.def_to, template, context)
         vals['cc'] = get_value(cr, uid, rel_model_ref, template.def_cc, template, context)
         vals['bcc'] = get_value(cr, uid, rel_model_ref, template.def_bcc, template, context)
+        vals['reply_to'] = get_value(cr, uid, rel_model_ref, template.reply_to, template, context)
+        if template.message_id:
+            vals['message_id'] = get_value(cr, uid, rel_model_ref, template.message_id, template, context)
+        elif template.track_campaign_item:
+            vals['message_id'] = tools.misc.generate_tracking_message_id(rel_model_ref)
         vals['subject'] = get_value(cr, uid, rel_model_ref, template.def_subject, template, context)
         vals['body_text'] = get_value(cr, uid, rel_model_ref, template.def_body_text, template, context)
         vals['body_html'] = get_value(cr, uid, rel_model_ref, template.def_body_html, template, context)
         vals['report'] = get_value(cr, uid, rel_model_ref, template.file_name, template, context)
         return {'value':vals}
-        
+
 email_template_preview()
 
 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: