edgar 7 éve
commit
9c22d11c68

+ 3 - 0
__init__.py

@@ -0,0 +1,3 @@
+# -*- coding: utf-8 -*-
+
+from . import models

+ 68 - 0
__openerp__.py

@@ -0,0 +1,68 @@
+# -*- coding: utf-8 -*-
+{
+    'name': "VietERP Mailbox",
+
+    'summary': """
+        Simple Odoo mailbox""",
+
+    'description': """
+1. Main features:
+    - Sending email from odoo
+    - Receiving email from odoo
+    - Composing email from odoo
+    - Choosing template when composing email
+
+2. Why choose this?
+    - Quickly compose email by using template
+    - Don't need to setup any email client on computer
+    - Can access it from any where
+
+3. Settings:
+    - To receiving email, you should follow below:
+    Step1:
+    <img src="/vieterp_mailbox/static/description/step1.png"/>
+    Step2:
+    <img src="/vieterp_mailbox/static/description/step2.png"/>
+    Step3:
+    <img src="/vieterp_mailbox/static/description/step3.png"/>
+
+4. Support:
+    For any feedback, please send email to info@vieterp.net
+
+    """,
+
+    'author': "VietERP / Sang",
+    'website': "http://www.vieterp.net",
+
+    # Categories can be used to filter modules in modules listing
+    # Check https://github.com/odoo/odoo/blob/master/odoo/addons/base/module/module_data.xml
+    # for the full list
+    'category': 'Discuss',
+    'version': '1.2',
+
+    # any module necessary for this one to work correctly
+    'depends': [
+        'base',
+        'mail',
+        'fetchmail',
+    ],
+
+    # always loaded
+    'data': [
+        'data/cron.xml',
+        'data/data.xml',
+        'security/record_rules.xml',
+        'security/ir.model.access.csv',
+        'views/mail_mail_views.xml',
+        'views/fetchmail_server_views.xml',
+        'views/mail_server_source_views.xml',
+    ],
+    # only loaded in demonstration mode
+    'demo': [
+    ],
+    'images': [
+        'static/description/icon.png'
+    ],
+    'installable': True,
+    'application': True,
+}

+ 16 - 0
data/cron.xml

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data noupdate="1">
+        <record id="ir_cron_mail_gateway_action" model="ir.cron">
+            <field name="name">Fetchmail Inbox Service</field>
+            <field name="interval_number">1</field>
+            <field name="interval_type">minutes</field>
+            <field name="numbercall">-1</field>
+            <field name="doall" eval="False"/>
+            <field name="model">fetchmail.server.inbox</field>
+            <field name="function">_fetch_mails</field>
+            <field name="args">()</field>
+            <field name="active" eval="True"/>
+        </record>
+    </data>
+</openerp>

+ 12 - 0
data/data.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data>
+        <record id="mail_source_1" model="mail.server.source">
+            <field name="name">Gmail - POP</field>
+            <field name="type">pop</field>
+            <field name="server">pop.gmail.com</field>
+            <field name="port">995</field>
+            <field name="is_ssl">1</field>
+        </record>
+    </data>
+</openerp>

+ 5 - 0
models/__init__.py

@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+
+from . import mail_inbox
+from . import mail_server_source
+from . import fetchmail_server

+ 49 - 0
models/fetchmail_server.py

@@ -0,0 +1,49 @@
+# -*- coding: utf-8 -*-
+from imaplib import IMAP4, IMAP4_SSL
+from poplib import POP3, POP3_SSL
+from openerp import tools, models, fields, api
+MAIL_TIMEOUT = 60
+
+class vieterp_fetchmail_server(models.Model):
+    _inherit = 'fetchmail.server'
+    _name = 'fetchmail.server.inbox'
+
+    @api.model
+    def _def_object_id(self):
+        model_obj = self.env['ir.model']
+        model = model_obj.search([('model', '=', 'mail.inbox')], limit = 1)
+        if model:
+            return model[0].id
+        return False
+
+    source_id = fields.Many2one('mail.server.source', string='Mail Source')
+    object_id = fields.Many2one('ir.model', string="Create a New Record", default=_def_object_id)
+
+    @api.multi
+    def fetch_mail(self):
+        result = super(vieterp_fetchmail_server, self).fetch_mail()
+        return True
+
+    @api.multi
+    def connect(self):
+        if self.source_id and self.source_id.id:
+            self.ensure_one()
+            if self.source_id.type == 'imap':
+                if self.source_id.is_ssl:
+                    connection = IMAP4_SSL(self.source_id.server, int(self.source_id.port))
+                else:
+                    connection = IMAP4(self.source_id.server, int(self.source_id.port))
+                connection.login(self.user, self.password)
+            elif self.type == 'pop':
+                if self.source_id.is_ssl:
+                    connection = POP3_SSL(self.source_id.server, int(self.source_id.port))
+                else:
+                    connection = POP3(self.source_id.server, int(self.source_id.port))
+                # TODO: use this to remove only unread messages
+                # connection.user("recent:"+server.user)
+                connection.user(self.user)
+                connection.pass_(self.password)
+            # Add timeout on socket
+            connection.sock.settimeout(MAIL_TIMEOUT)
+            return connection
+        return super(vieterp_fetchmail_server, self).connect()

+ 83 - 0
models/mail_inbox.py

@@ -0,0 +1,83 @@
+# -*- coding: utf-8 -*-
+from lxml import etree
+from openerp import tools, models, fields, api
+from openerp.tools.translate import _
+
+class vieterp_mail_inbox(models.Model):
+    _inherit = ['mail.mail']
+    _name = 'mail.inbox'
+
+    fetchmail_server_id = fields.Many2one('fetchmail.server.inbox', "Inbound Mail Server", readonly=True, index=True,
+                                          oldname='server_id')
+    template_id = fields.Many2one('email.template', string='Mail Template', select=True)
+    state = fields.Selection([
+        ('inbox', 'Inbox'),
+        ('outgoing', 'Outgoing'),
+        ('sent', 'Sent'),
+        ('received', 'Received'),
+        ('exception', 'Delivery Failed'),
+        ('cancel', 'Cancelled'),
+    ], 'Status', readonly=True, copy=False, default='outgoing')
+
+    @api.model
+    def message_new(self, msg_dict, custom_values=None):
+        self = self.with_context(default_user_id=False)
+        mail_data = {
+            'subject': msg_dict.get('subject') or _("No Subject"),
+            'email_from': msg_dict.get('from'),
+            'email_to': msg_dict.get('to'),
+            'email_cc': msg_dict.get('cc'),
+            'partner_id': msg_dict.get('author_id', False),
+            'body_html': msg_dict.get('body', ''),
+            'attachment_ids': msg_dict.get('attachments', []),
+            'state': 'inbox',
+        }
+        result = self.create(mail_data)
+        return result
+
+    @api.multi
+    @api.returns('mail.message', lambda value: value.id)
+    def message_post(self, subtype=None, **kwargs):
+        message_data = {
+            'subject': kwargs.get('subject'),
+            'date': kwargs.get('date'),
+            'body': kwargs.get('body'),
+            'email_from': kwargs.get('email_from'),
+            'reply_to': kwargs.get('email_from'),
+        }
+        return self.env['mail.message'].create(message_data)
+
+    # @api.model
+    # def fields_view_get(self, view_id=None, view_type=False, toolbar=False, submenu=False):
+    #     context = self._context
+    #     result = super(vieterp_mail_inbox, self).fields_view_get(view_id, view_type, toolbar, submenu)
+    #     if view_type == 'form':
+    #         current_id = context.get('active_id', False)
+    #         my_state = self.browse(current_id).state
+    #         if my_state in ['inbox', 'outgoing']:
+    #             doc = etree.XML(result['arch'])
+    #             for node in doc.xpath('//form'):
+    #                 node.set('edit', 'true')
+    #             result['arch'] = etree.tostring(doc)
+    #     return result
+
+    @api.onchange('template_id')  # if template are changed, call method
+    def check_template_change(self):
+        """ - mass_mailing: we cannot render, so return the template values
+            - normal mode: return rendered values """
+        if self.template_id and self.template_id.id:
+            self.subject = self.template_id.subject
+            self.body_html = self.template_id.body_html
+            self.reply_to = self.template_id.reply_to
+            self.mail_server_id = self.template_id.mail_server_id
+            if self.template_id.attachment_ids:
+                self.attachment_ids = [att.id for att in template.attachment_ids]
+            if self.template_id.mail_server_id:
+                self.mail_server_id = self.template_id.mail_server_id.id
+            if self.template_id.user_signature and self.body_html:
+                signature = self.env['res.users'].browse(self._uid).signature
+                self.body = tools.append_content_to_html(self.body, signature, plaintext=False)
+        else:
+            if not self.body_html:
+                signature = self.env['res.users'].browse(self._uid).signature
+                self.body_html = signature

+ 6 - 0
models/mail_server_source.py

@@ -0,0 +1,6 @@
+# -*- coding: utf-8 -*-
+from openerp import tools, models, fields, api
+
+class vieterp_mail_server_source(models.Model):
+    _inherit = 'fetchmail.server'
+    _name = 'mail.server.source'

+ 5 - 0
security/ir.model.access.csv

@@ -0,0 +1,5 @@
+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+access_mail_inbox,main.inbox,model_mail_inbox,base.group_user,1,1,1,1
+access_mail_server_source,main.server_source,model_mail_server_source,base.group_system,1,1,1,1
+access_mail_server_source_read,main.server_source_read,model_mail_server_source,base.group_user,1,0,0,0
+access_fetchmail_server_inbox,fetchmail.server.inbox,model_fetchmail_server_inbox,base.group_user,1,1,1,1

+ 26 - 0
security/record_rules.xml

@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data>
+        <record model="ir.rule" id="fetchmail_server_inbox_user_rule">
+             <field name="name">Inbox Server: User</field>
+             <field name="model_id" ref="model_fetchmail_server_inbox"></field>
+             <field name="groups" eval="[(4,ref('base.group_user'))]"></field>
+             <field name="domain_force">[('create_uid', '=', user.id)]</field>
+             <field eval="1" name="perm_write"></field>
+             <field eval="1" name="perm_read"></field>
+             <field eval="1" name="perm_unlink"></field>
+             <field eval="1" name="perm_create"></field>
+        </record>
+
+        <record model="ir.rule" id="mail_inbox_user_rule">
+             <field name="name">Inbox Mail: User</field>
+             <field name="model_id" ref="model_mail_inbox"></field>
+             <field name="groups" eval="[(4,ref('base.group_user'))]"></field>
+             <field name="domain_force">[('create_uid', '=', user.id)]</field>
+             <field eval="1" name="perm_write"></field>
+             <field eval="1" name="perm_read"></field>
+             <field eval="1" name="perm_unlink"></field>
+             <field eval="1" name="perm_create"></field>
+        </record>
+    </data>
+</openerp>

BIN
static/description/compose.png


BIN
static/description/icon.png


+ 53 - 0
static/description/index.html

@@ -0,0 +1,53 @@
+<section class="oe_container">
+    <div class="oe_row oe_spaced">
+        <h2 class="oe_slogan" style="color:#875A7B;">1. Main features</h2>
+        <ol>
+            <li>Sending email from odoo</li>
+            <li>Receiving email from odoo</li>
+            <li>Composing email from odoo</li>
+            <li>Choosing template when composing email</li>
+        </ol>
+        <div class="oe_demo oe_picture or_screenshot">
+            <img src="intro.png">
+        </div>
+    </div>
+</section>
+
+<section class="oe_container">
+    <div class="oe_row oe_spaced">
+        <h2 class="oe_slogan" style="color:#875A7B;">2. Why choose this?</h2>
+        <ol>
+            <li>Quickly compose email by using template</li>
+            <li>Don't need to setup any email client on computer</li>
+            <li>Can access it from any where</li>
+        </ol>
+        <div class="oe_demo oe_picture or_screenshot">
+            <img src="compose.png">
+        </div>
+    </div>
+</section>
+
+<section class="oe_container">
+    <div class="oe_row oe_spaced">
+        <h2 class="oe_slogan" style="color:#875A7B;">3. Settings</h2>
+        <p>Step1</p>
+        <div class="oe_demo oe_picture or_screenshot">
+            <img src="step1.png">
+        </div>
+        <p>Step2</p>
+        <div class="oe_demo oe_picture or_screenshot">
+            <img src="step2.png">
+        </div>
+        <p>Step3</p>
+        <div class="oe_demo oe_picture or_screenshot">
+            <img src="step3.png">
+        </div>
+    </div>
+</section>
+
+<section class="oe_container">
+    <div class="oe_row oe_spaced">
+        <h2 class="oe_slogan" style="color:#875A7B;">4. Support</h2>
+        <p>For any feedback, please send email to <a href="mailto:info@vieterp.net">info@vieterp.net</a> or website <a href="http://www.vieterp.net">www.vieterp.net</a></p>
+    </div>
+</section>

BIN
static/description/intro.png


BIN
static/description/step1.png


BIN
static/description/step2.png


BIN
static/description/step3.png


+ 82 - 0
views/fetchmail_server_views.xml

@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<openerp>
+    <data>
+        <record id="view_email_server_inbox_tree" model="ir.ui.view">
+            <field name="name">fetchmail.server.inbox.list</field>
+            <field name="model">fetchmail.server.inbox</field>
+            <field name="arch" type="xml">
+                <tree decoration-info="state == 'draft'" string="POP/IMAP Servers">
+                    <field name="source_id"/>
+                    <field name="name"/>
+                    <field name="user"/>
+                    <field name="date"/>
+                    <field name="state"/>
+                </tree>
+            </field>
+        </record>
+
+        <record id="view_email_server_inbox_form" model="ir.ui.view">
+            <field name="name">fetchmail.server.inbox.form</field>
+            <field name="model">fetchmail.server.inbox</field>
+            <field name="arch" type="xml">
+                <form string="Incoming Mail Server">
+                    <header attrs="{'invisible' : [('type', '=', 'local')]}">
+                        <button string="Test &amp; Confirm" type="object" name="button_confirm_login" states="draft"/>
+                        <button string="Fetch Now" type="object" name="fetch_mail" states="done"/>
+                        <button string="Reset Confirmation" type="object" name="set_draft" states="done"/>
+                        <field name="state" widget="statusbar"/>
+                    </header>
+                    <sheet>
+                        <group col="4">
+                            <field name="name"/>
+                            <field name="source_id" required="True"/>
+                            <field name="type" invisible="1"/>
+                        </group>
+                        <group>
+                            <group string="Login Information">
+                                <field name="user" required="True"/>
+                                <field name="password" required="True" password="True"/>
+                                <field name="date"/>
+                            </group>
+                        </group>
+                    </sheet>
+                </form>
+            </field>
+        </record>
+
+        <record id="view_email_server_inbox_search" model="ir.ui.view">
+            <field name="name">fetchmail.server.inbox.search</field>
+            <field name="model">fetchmail.server.inbox</field>
+            <field name="arch" type="xml">
+                <search string="Search Incoming Mail Servers">
+                    <field name="name" string="Incoming Mail Server"/>
+                    <filter string="IMAP" domain="[('type','=','imap')]" help="Server type IMAP."/>
+                    <filter string="POP" domain="[('type','=','pop')]" help="Server type POP."/>
+                    <separator/>
+                    <filter string="SSL" domain="[('is_ssl','=',True)]" help="If SSL required."/>
+                </search>
+            </field>
+        </record>
+
+        <record id="action_email_server_inbox_tree" model="ir.actions.act_window">
+            <field name="name">Mail Servers</field>
+            <field name="res_model">fetchmail.server.inbox</field>
+            <field name="view_type">form</field>
+            <field name="view_mode">tree,form</field>
+            <field name="context">{}</field>
+            <field name="view_id" ref="view_email_server_inbox_tree"/>
+            <field name="search_view_id" ref="view_email_server_inbox_search"/>
+        </record>
+
+
+        <menuitem id="menu_setting" name="Settings" parent="menu_email_root"/>
+        <menuitem
+            parent="menu_setting"
+            id="menu_action_fetchmail_server_tree"
+            action="action_email_server_inbox_tree"
+            name="Mail Servers"
+            sequence="14"
+            groups="base.group_user"
+        />
+    </data>
+</openerp>

+ 147 - 0
views/mail_mail_views.xml

@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data>
+        <record model="ir.ui.view" id="view_mail_inbox_search">
+            <field name="name">mail.inbox.search</field>
+            <field name="model">mail.inbox</field>
+            <field name="arch" type="xml">
+                <search string="Email Search">
+                    <field name="email_from" filter_domain="['|', '|',('email_from','ilike',self), ('email_to','ilike',self), ('subject','ilike',self)]" string="Email"/>
+                    <field name="date"/>
+                    <filter name="received" string="Received" domain="[('state','=','received')]"/>
+                    <filter name="outgoing" string="Outgoing" domain="[('state','=','outgoing')]"/>
+                    <filter name="sent" string="Sent" domain="[('state','=','sent')]"/>
+                    <filter name="exception" string="Failed" domain="[('state','=','exception')]"/>
+                    <separator/>
+                    <filter name="type_email" string="Email" domain="[('message_type','=','email')]"/>
+                    <filter name="type_comment" string="Comment" domain="[('message_type','=','comment')]"/>
+                    <filter name="type_notification" string="Notification" domain="[('message_type','=','notification')]"/>
+                    <group expand="0" string="Extended Filters...">
+                        <field name="author_id"/>
+                        <field name="recipient_ids"/>
+                        <field name="model"/>
+                        <field name="res_id"/>
+                    </group>
+                    <group expand="0" string="Group By">
+                        <filter string="Status" name="status" domain="[]" context="{'group_by':'state'}"/>
+                        <filter string="Author" name="author" context="{'group_by':'author_id'}"/>
+                        <filter string="Thread" name="thread" domain="[]" context="{'group_by':'message_id'}"/>
+                        <filter string="Month" name="month" help="Creation Month" domain="[]" context="{'group_by':'date'}"/>
+                    </group>
+                </search>
+            </field>
+        </record>
+
+        <record model="ir.ui.view" id="view_mail_inbox_tree">
+            <field name="name">mail.inbox.tree</field>
+            <field name="model">mail.inbox</field>
+            <field name="arch" type="xml">
+                <tree>
+                    <field name="date"/>
+                    <field name="create_uid"/>
+                    <field name="subject"/>
+                    <field name="author_id"/>
+                    <field name="partner_ids"/>
+                </tree>
+            </field>
+        </record>
+
+        <record model="ir.ui.view" id="view_mail_inbox_form">
+            <field name="name">mail.inbox.form</field>
+            <field name="model">mail.inbox</field>
+            <field name="arch" type="xml">
+                <form string="Message" edit="false">
+                    <header>
+                        <button name="send" string="Send Now" type="object" states='outgoing' class="oe_highlight"/>
+                        <button name="mark_outgoing" string="Retry" type="object" states='exception,cancel'/>
+                        <button name="cancel" string="Cancel" type="object" states='outgoing'/>
+                        <field name="state" widget="statusbar" statusbar_visible="outgoing,sent,received,exception,cancel"/>
+                    </header>
+                    <sheet>
+                        <div class="oe_title">
+                            <h1><field name="subject" placeholder="Subject..." required="True"/></h1>
+                        </div>
+                        <group col="8">
+                            <group colspan="8">
+                                <field name="partner_ids" widget="many2many_tags" invisible="1"/>
+                                <field name="email_to" required="True"/>
+                                <field name="email_cc"/>
+                                <field name="reply_to"/>
+                                <field name="template_id"
+                                       domain="[('model_id.model','=','mail.inbox')]"
+                                       context="{'default_model': 'mail.inbox', 'default_body_html': body_html, 'default_subject': subject, 'default_user_signature': True}"/>
+                                <field name="author_id" invisible="1"/>
+                                <field name="email_from" invisible="1"/>
+                                <field name="date" invisible="1"/>
+                                <field name="model" invisible="1"/>
+                                <field name="res_id" invisible="1"/>
+                                <field name="parent_id" invisible="1"/>
+                                <field name="subtype_id" invisible="1"/>
+                            </group>
+                        </group>
+                        <notebook>
+                            <page string="Body">
+                                <field name="body_html" widget="html" required="True"/>
+                            </page>
+                            <page string="Attachments">
+                                <field name="attachment_ids"/>
+                            </page>
+                        </notebook>
+                    </sheet>
+                </form>
+            </field>
+        </record>
+
+        <record id="action_mail_inbox" model="ir.actions.act_window">
+            <field name="name">Inbox</field>
+            <field name="type">ir.actions.act_window</field>
+            <field name="res_model">mail.inbox</field>
+            <field name="view_type">form</field>
+            <field name="view_mode">tree,form</field>
+            <field name="context">{}</field>
+            <field name="domain">[('state', '=', 'inbox')]</field>
+            <field name="search_view_id" ref="view_mail_inbox_search"/>
+        </record>
+
+        <record id="action_mail_draft" model="ir.actions.act_window">
+            <field name="name">Draft</field>
+            <field name="type">ir.actions.act_window</field>
+            <field name="res_model">mail.inbox</field>
+            <field name="view_type">form</field>
+            <field name="view_mode">tree,form</field>
+            <field name="context">{}</field>
+            <field name="domain">[('state', '=', 'outgoing')]</field>
+            <field name="search_view_id" ref="view_mail_inbox_search"/>
+        </record>
+
+        <record id="action_mail_outbox" model="ir.actions.act_window">
+            <field name="name">Outbox</field>
+            <field name="type">ir.actions.act_window</field>
+            <field name="res_model">mail.inbox</field>
+            <field name="view_type">form</field>
+            <field name="view_mode">tree,form</field>
+            <field name="context">{}</field>
+            <field name="domain">['|',('state', '=', 'exception'),('state', '=', 'cancel')]</field>
+            <field name="search_view_id" ref="view_mail_inbox_search"/>
+        </record>
+
+        <record id="action_mail_sent" model="ir.actions.act_window">
+            <field name="name">Sent</field>
+            <field name="type">ir.actions.act_window</field>
+            <field name="res_model">mail.inbox</field>
+            <field name="view_type">form</field>
+            <field name="view_mode">tree,form</field>
+            <field name="context">{}</field>
+            <field name="domain">['|',('state', '=', 'sent'),('state', '=', 'received')]</field>
+            <field name="search_view_id" ref="view_mail_inbox_search"/>
+        </record>
+
+        <menuitem name="Mails" id="menu_email_root"/>
+        <menuitem id="menu_mails" name="Mails" parent="menu_email_root"/>
+
+        <menuitem id="menu_mail_inbox" sequence="10" action="action_mail_inbox" parent="menu_mails" groups="base.group_user"/>
+        <menuitem id="menu_mail_draft" sequence="20" action="action_mail_draft" parent="menu_mails" groups="base.group_user"/>
+        <menuitem id="menu_mail_outbox" sequence="30" action="action_mail_outbox" parent="menu_mails" groups="base.group_user"/>
+        <menuitem id="menu_mail_sent" sequence="40" action="action_mail_sent" parent="menu_mails" groups="base.group_user"/>
+    </data>
+</openerp>

+ 73 - 0
views/mail_server_source_views.xml

@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data>
+        <record id="view_mail_server_source_tree" model="ir.ui.view">
+            <field name="name">mail.server.source.list</field>
+            <field name="model">mail.server.source</field>
+            <field name="arch" type="xml">
+                <tree string="Source">
+                    <field name="name"/>
+                    <field name="type"/>
+                    <field name="is_ssl"/>
+                    <field name="server"/>
+                    <field name="port"/>
+                    <field name="state" invisible="1"/>
+                </tree>
+            </field>
+        </record>
+
+        <record id="view_mail_server_source_form" model="ir.ui.view">
+            <field name="name">mail.server.source.form</field>
+            <field name="model">mail.server.source</field>
+            <field name="arch" type="xml">
+                <form string="Incoming Mail Server" edit="0">
+                    <sheet>
+                        <group col="4">
+                            <field name="name"/>
+                            <field name="state" invisible="1"/>
+                        </group>
+                        <group string="Server Information">
+                            <group>
+                                <field name="type"/>
+                                <field name="is_ssl"/>
+                            </group>
+                            <group>
+                                <field name="server" colspan="2" attrs="{'required' : [('type', '!=', 'local')]}" />
+                                <field name="port" required="1" attrs="{'required' : [('type', '!=', 'local')]}" />
+                            </group>
+                        </group>
+                    </sheet>
+                </form>
+            </field>
+        </record>
+
+        <record id="view_mail_server_source_search" model="ir.ui.view">
+            <field name="name">mail.server.source.search</field>
+            <field name="model">mail.server.source</field>
+            <field name="arch" type="xml">
+                <search string="Search Mail Servers">
+                    <field name="name" string="Mail Server"/>
+                </search>
+            </field>
+        </record>
+
+        <record id="action_mail_server_source_tree" model="ir.actions.act_window">
+            <field name="name">Mail Servers</field>
+            <field name="res_model">mail.server.source</field>
+            <field name="view_type">form</field>
+            <field name="view_mode">tree,form</field>
+            <field name="view_id" ref="view_mail_server_source_tree"/>
+            <field name="search_view_id" ref="view_mail_server_source_search"/>
+        </record>
+
+        <menuitem id="menu_setting" name="Settings" parent="menu_email_root"/>
+        <menuitem
+            parent="menu_setting"
+            id="menu_action_mail_server_source_tree"
+            action="action_mail_server_source_tree"
+            name="Source"
+            sequence="14"
+            groups="base.group_user"
+        />
+    </data>
+</openerp>