{"id":11265,"date":"2026-06-05T16:29:47","date_gmt":"2026-06-05T10:59:47","guid":{"rendered":"https:\/\/tenthplanet.in\/blogs\/?p=11265"},"modified":"2026-06-07T12:15:47","modified_gmt":"2026-06-07T06:45:47","slug":"link-odoo-contacts-to-mailing-lists-data-consent-setup","status":"publish","type":"post","link":"https:\/\/tenthplanet.in\/blogs\/link-odoo-contacts-to-mailing-lists-data-consent-setup\/","title":{"rendered":"Link Odoo Contacts to Mailing Lists: Data + Consent Setup"},"content":{"rendered":"\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<h3 class=\"wp-block-heading\">The problem most Odoo marketing setups have<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Most Odoo email marketing setups force a bad choice: either you target <strong>res.partner<\/strong> directly (which gives you data-driven segmentation but no topic-level consent), or you target <strong>mailing.list<\/strong> (which gives you consent management but no easy access to customer data). The truth is you need <em>both<\/em>. This guide shows you how to link the two tables so you can run consent-compliant campaigns that filter by customer data \u2014 install date, product type, purchase history, and any custom field you&#8217;ve added<\/p>\n<\/blockquote>\n\n\n\n<h3 class=\"wp-block-heading\">The Five-Minute Summary<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Odoo stores contacts in two tables: res.partner (customer data) and mailing.contact (marketing subscribers). They aren&#8217;t linked by default.<\/li>\n\n\n\n<li>For most businesses with topic-based consent needs (Newsletter, Promotions, Tips, Service Reminders), the right setup is <strong>linked tables<\/strong> \u2014 every res.partner has a matching mailing.contact connected via a partner_id reference.<\/li>\n\n\n\n<li>Marketing campaigns then target mailing.contact, filter by mailing list subscription (consent), and traverse partner_id to access res.partner data (segmentation).<\/li>\n\n\n\n<li>Enforce unique email on both tables. Use Automation Rules to auto-create and auto-link. Configure mailing lists with &#8220;Show in Preferences&#8221; so customers manage topics individually.<\/li>\n\n\n\n<li>Operational emails (orders, invoices, tickets) continue to flow through res.partner and bypass the marketing blacklist \u2014 always delivered.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">1. Why Odoo has two contact tables<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">If you&#8217;re new to Odoo email marketing, here&#8217;s the surprise you&#8217;ll discover within your first week: Odoo stores your customers in <em>two completely separate tables<\/em>, and they aren&#8217;t linked.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>res.partner<\/strong> is the master contact table used by Sales, CRM, Invoicing, Inventory, Helpdesk, Field Service, eCommerce, and almost every other module. When a customer buys something, books an appointment, or submits a contact form, they live here.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>mailing.contact<\/strong> is a separate table that exists only inside the Email Marketing module. It holds newsletter subscribers, imported marketing contacts, and anyone added to a mailing list. By default, it has no foreign key to res.partner.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This separation was a deliberate design choice \u2014 newsletter subscribers from a public website don&#8217;t need billing addresses, tax IDs, or customer ranks. They just need an email and a few preferences. But for businesses with real customers who also need marketing, the lack of an automatic link causes:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The same person stored in both tables with no connection<\/li>\n\n\n\n<li>Marketing campaigns missing customers (because they&#8217;re in res.partner but not in any mailing list)<\/li>\n\n\n\n<li>Newsletter campaigns hitting customers twice (once as res.partner, once as mailing.contact)<\/li>\n\n\n\n<li>No way to filter marketing campaigns by sales data (orders, install date, product type) when targeting a mailing list<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">2. Decision Tree: which architecture do you need?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Before choosing an architecture, answer two questions about your business:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<h4 class=\"wp-block-heading\">Architecture Decision Tree<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Q1: Do customers need to choose <em>which<\/em> topics of marketing they receive?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Examples:<\/strong> &#8220;I want product tips but not promotions&#8221; \/ &#8220;Send me service reminders but not newsletter&#8221;<br>If <strong>YES<\/strong> \u2192 you need a <strong>mailing.list-based consent layer<\/strong> \u2192 continue to Q2.<br>If <strong>NO<\/strong> (one-size-fits-all marketing) \u2192 simpler architecture: target res.partner directly with the global blacklist as the only unsubscribe option.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Q2: Do your marketing emails need to filter by customer data (orders, install dates, product type, custom fields)?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If <strong>YES<\/strong> \u2192 <strong>linked-tables architecture (this guide)<\/strong> \u2014 target mailing.contact, filter by list subscription, traverse partner_id for segmentation.<br>If <strong>NO<\/strong> (purely list-based campaigns) \u2192 traditional mailing.list targeting works fine, no linking needed.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">If you answered yes to both questions \u2014 which most B2C and service businesses do \u2014 the rest of this guide is for you.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">3. The Linked-Tables Architecture in Detail<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In the linked-tables architecture, every res.partner with an email automatically gets a paired mailing.contact, connected via a partner_id Many2one field. The mailing.contact subscribes to mailing lists for topic-level consent, and any campaign can traverse partner_id to access res.partner data.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"780\" height=\"409\" src=\"https:\/\/tenthplanet.in\/blogs\/wp-content\/uploads\/sites\/21\/2026\/06\/image-13.png\" alt=\"\" class=\"wp-image-11269\" style=\"width:780px;height:auto\" srcset=\"https:\/\/tenthplanet.in\/blogs\/wp-content\/uploads\/sites\/21\/2026\/06\/image-13.png 780w, https:\/\/tenthplanet.in\/blogs\/wp-content\/uploads\/sites\/21\/2026\/06\/image-13-300x157.png 300w, https:\/\/tenthplanet.in\/blogs\/wp-content\/uploads\/sites\/21\/2026\/06\/image-13-768x403.png 768w\" sizes=\"auto, (max-width: 780px) 100vw, 780px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">The Three Roles Each Table Plays<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Table<\/th><th>Role<\/th><th>What it stores<\/th><\/tr><tr><td>res.partner<\/td><td>Customer master + segmentation source<\/td><td>Identity, sales history, custom data fields (install date, product type, etc.)<\/td><\/tr><tr><td>mailing.contact<\/td><td>Marketing bridge + subscription holder<\/td><td>Email, partner_id link, list memberships, per-list opt-out flags<\/td><\/tr><tr><td>mailing.list<\/td><td>Topic-level consent grouping<\/td><td>List name (Newsletter, Promotions, etc.), Show in Preferences setting<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">4. The Recommended Rules and Auto-Linking<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">You need a partner_id field on mailing.contact \u2014 this is the keystone of the architecture.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Rule 1 \u2014 On res.partner Create: Auto-Create and Link mailing.contact<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Linking res.partner \u2194 mailing.contact? <br>\u2014 A one-directional link for segmentation is fine. A mandatory bidirectional 1:1 is not.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Rule 2 \u2014 On res.partner Email Change: Propagate to mailing.contact<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">If a customer updates their email, the linked mailing.contact must update too. Trigger: On Update, watching the email field.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Rule 3 \u2014 On mailing.contact Create: Reverse-Link to Existing res.partner<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">If a newsletter signup matches an existing customer&#8217;s email, link them.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">5. Configuring Mailing Lists as Your Consent Layer<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The mailing.list table is your topic-level consent layer. Each list represents one category of marketing emails customers can opt into or out of.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">The Standard Four-List Structure<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Almost every business should start with these four lists:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>List Name<\/th><th>Email Types<\/th><th>Default Subscribe?<\/th><\/tr><tr><td>Newsletter<\/td><td>Monthly updates, blog roundups, education<\/td><td>Yes<\/td><\/tr><tr><td>Promotions &amp; Offers<\/td><td>Seasonal deals, discounts, sales<\/td><td>Yes (easy opt-out)<\/td><\/tr><tr><td>Product Tips &amp; Care<\/td><td>How-to content, maintenance, best practices<\/td><td>Yes<\/td><\/tr><tr><td>Service Reminders<\/td><td>Renewal, maintenance, reorder prompts<\/td><td>Yes (clearly labelled)<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Add the x_default_subscribe Field<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Add a custom Boolean field x_default_subscribe on the mailing.list model via Studio. Tick it for the lists you want every new customer to be auto-subscribed to. The Automation Rule from Section 5 reads this field and subscribes new customers accordingly.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">6. Campaign Targeting \u2014 The New Pattern<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The targeting pattern in the linked architecture is fundamentally different from the traditional res.partner-direct approach. Here&#8217;s the formula:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"780\" height=\"209\" src=\"https:\/\/tenthplanet.in\/blogs\/wp-content\/uploads\/sites\/21\/2026\/06\/image-14.png\" alt=\"\" class=\"wp-image-11270\" srcset=\"https:\/\/tenthplanet.in\/blogs\/wp-content\/uploads\/sites\/21\/2026\/06\/image-14.png 780w, https:\/\/tenthplanet.in\/blogs\/wp-content\/uploads\/sites\/21\/2026\/06\/image-14-300x80.png 300w, https:\/\/tenthplanet.in\/blogs\/wp-content\/uploads\/sites\/21\/2026\/06\/image-14-768x206.png 768w\" sizes=\"auto, (max-width: 780px) 100vw, 780px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Worked Example 1 \u2014 Cross-Sell Campaign<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Send a cross-sell email to customers who own Product A but not Product B, and who have consented to Promotions:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"780\" height=\"382\" src=\"https:\/\/tenthplanet.in\/blogs\/wp-content\/uploads\/sites\/21\/2026\/06\/image-15.png\" alt=\"\" class=\"wp-image-11271\" srcset=\"https:\/\/tenthplanet.in\/blogs\/wp-content\/uploads\/sites\/21\/2026\/06\/image-15.png 780w, https:\/\/tenthplanet.in\/blogs\/wp-content\/uploads\/sites\/21\/2026\/06\/image-15-300x147.png 300w, https:\/\/tenthplanet.in\/blogs\/wp-content\/uploads\/sites\/21\/2026\/06\/image-15-768x376.png 768w\" sizes=\"auto, (max-width: 780px) 100vw, 780px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Worked Example 2 \u2014 Service Reminder<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Send a service reminder to customers whose next service date is in 30 days, who have consented to Service Reminders:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"780\" height=\"341\" src=\"https:\/\/tenthplanet.in\/blogs\/wp-content\/uploads\/sites\/21\/2026\/06\/image-16.png\" alt=\"\" class=\"wp-image-11272\" srcset=\"https:\/\/tenthplanet.in\/blogs\/wp-content\/uploads\/sites\/21\/2026\/06\/image-16.png 780w, https:\/\/tenthplanet.in\/blogs\/wp-content\/uploads\/sites\/21\/2026\/06\/image-16-300x131.png 300w, https:\/\/tenthplanet.in\/blogs\/wp-content\/uploads\/sites\/21\/2026\/06\/image-16-768x336.png 768w\" sizes=\"auto, (max-width: 780px) 100vw, 780px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">7. Operational vs Marketing Emails (Still Relevant)<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The linked architecture is for <strong>marketing<\/strong> emails. <strong>Operational<\/strong> emails \u2014 order confirmations, invoices, delivery notifications, support tickets \u2014 continue to flow directly through res.partner via the mail.message pipeline. They bypass the blacklist and are always delivered.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>Aspect<\/th><th>Operational<\/th><th>Marketing<\/th><\/tr><tr><td>Trigger<\/td><td>Business event (sale, invoice, ticket)<\/td><td>Marketer \/ automation rule<\/td><\/tr><tr><td>Pipeline<\/td><td>mail.message \/ chatter<\/td><td>Email Marketing \/ Marketing Automation<\/td><\/tr><tr><td>Target<\/td><td>res.partner directly<\/td><td>mailing.contact (linked architecture)<\/td><\/tr><tr><td>Respects blacklist?<\/td><td>NO<\/td><td>YES<\/td><\/tr><tr><td>Respects per-list opt-out?<\/td><td>N\/A<\/td><td>YES<\/td><\/tr><tr><td>GDPR basis<\/td><td>Contract performance<\/td><td>Consent (opt-in)<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">8. Unsubscribe, Blacklist, and GDPR<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Two unsubscribe mechanisms work together in the linked architecture:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Per-List Opt-Out (Topic Level)<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">When customers click unsubscribe in a marketing email, they land on a preferences page showing every mailing list with &#8220;Show in Preferences&#8221; enabled. They can toggle individual lists \u2014 opt out of Promotions while staying subscribed to Service Reminders. This is the everyday consent tool.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Global Blacklist (All-Or-Nothing)<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The blacklist (model mail.blacklist) is the customer&#8217;s nuclear option. Once their email is on the blacklist, all marketing across every list and every campaign is blocked. Transactional emails (orders, invoices, tickets) still flow through.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Enable in Email Marketing \u2192 Configuration \u2192 Settings \u2192 Blacklist Option when Unsubscribing.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><strong>Common misunderstanding:<\/strong> Some practitioners think the blacklist doesn&#8217;t block marketing to res.partner-targeted campaigns. It does. Odoo checks the blacklist by email address regardless of which model is targeted. The blacklist applies equally to mailing.contact-targeted and res.partner-targeted campaigns. What it cannot do is differentiate between topics \u2014 that&#8217;s what mailing.list subscriptions are for.<\/p>\n<\/blockquote>\n\n\n\n<h2 class=\"wp-block-heading\">8. Challenges to accept<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Need custom Apps to avoid too much logic in Automation Rules<\/li>\n\n\n\n<li>Duplicate Email Storage\n<ul class=\"wp-block-list\">\n<li>Customer changes email, if automation fails.<\/li>\n\n\n\n<li>This creates synchronization risk.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>partner_id on mailing.contact is Custom<\/li>\n\n\n\n<li>Default Subscription Risk (GDPR)\n<ul class=\"wp-block-list\">\n<li>Automatically subscribe customers<\/li>\n\n\n\n<li>Promotions may require explicit opt-in<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Odoo Version upgrade needed <\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Final Thoughts<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The linked-tables architecture is more work to set up than the default Odoo configuration \u2014 uniqueness constraints, custom fields, three Automation Rules, a migration script. But once it&#8217;s in place, your email marketing setup does something most Odoo deployments cannot: combine data-driven segmentation with topic-level consent, all while keeping one record per customer and zero duplicate sends.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The three rules that make this architecture work:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Email is unique on both tables<\/strong> \u2014 enforced by Python constraints.<\/li>\n\n\n\n<li><strong>Every res.partner has a linked mailing.contact<\/strong> \u2014 maintained by Automation Rules.<\/li>\n\n\n\n<li><strong>Marketing campaigns target mailing.contact<\/strong> \u2014 filter by list subscription for consent, traverse partner_id for segmentation.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">Set this up once, document it for your team, and your Odoo email marketing will be cleaner than most enterprise CRM deployments.<\/p>\n\n\n\n<h3 class=\"wp-block-heading has-text-align-center\">Need help implementing the linked-tables architecture?<\/h3>\n\n\n\n<p class=\"has-text-align-center wp-block-paragraph\">TenthPlanet&#8217;s Odoo experts deploy this setup for service businesses, eCommerce, and B2B operations \u2014 including the custom constraints, Automation Rules, migration scripts, and campaign templates.<\/p>\n\n\n\n<div class=\"wp-block-buttons is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-fe48e5de wp-block-buttons-is-layout-flex\">\n<div class=\"wp-block-button\"><a class=\"wp-block-button__link has-text-align-center wp-element-button\" href=\"https:\/\/tenthplanet.in\/getintouch\/\">Get in touch<\/a><\/div>\n<\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>The problem most Odoo marketing setups have Most Odoo email marketing setups force a bad choice: either you target res.partner [&hellip;]<\/p>\n","protected":false},"author":12,"featured_media":11279,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[4],"tags":[85,1037,23],"class_list":["post-11265","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-odoo","tag-crm","tag-email-marketing","tag-odoo"],"acf":[],"_links":{"self":[{"href":"https:\/\/tenthplanet.in\/blogs\/wp-json\/wp\/v2\/posts\/11265","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/tenthplanet.in\/blogs\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/tenthplanet.in\/blogs\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/tenthplanet.in\/blogs\/wp-json\/wp\/v2\/users\/12"}],"replies":[{"embeddable":true,"href":"https:\/\/tenthplanet.in\/blogs\/wp-json\/wp\/v2\/comments?post=11265"}],"version-history":[{"count":7,"href":"https:\/\/tenthplanet.in\/blogs\/wp-json\/wp\/v2\/posts\/11265\/revisions"}],"predecessor-version":[{"id":11287,"href":"https:\/\/tenthplanet.in\/blogs\/wp-json\/wp\/v2\/posts\/11265\/revisions\/11287"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/tenthplanet.in\/blogs\/wp-json\/wp\/v2\/media\/11279"}],"wp:attachment":[{"href":"https:\/\/tenthplanet.in\/blogs\/wp-json\/wp\/v2\/media?parent=11265"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tenthplanet.in\/blogs\/wp-json\/wp\/v2\/categories?post=11265"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tenthplanet.in\/blogs\/wp-json\/wp\/v2\/tags?post=11265"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}