Skip to Content

Odoo 19 Email Templates: How the 'To' Field Actually Works

The From field on an Odoo email template gets all the attention because it's the one clients actually notice: wrong name in their customer's inbox, easy to spot. The To field causes fewer complaints, but only because when it's wrong, mail just goes nowhere and nobody notices until a customer calls asking where their invoice is.

Where the From field is a layered fallback chain (salesperson, then company, then whoever's logged in), the To field mostly works a different way: a single checkbox called Default Recipients. When it's on, Odoo ignores any custom recipient logic on the template and just sends to whatever contact the record itself already points to. When it's off, the template has to say explicitly who the recipient is.

Same Example: Sales: Send Quotation

Pull up the same "Sales: Send Quotation" template from the From-field side of this, flip to its Settings tab, and the recipient side looks almost anticlimactic. Default Recipients is checked, and both of the fields that could override it, email_to and partner_to, are blank.

That's the whole rule for this template: the quote goes to the customer already attached to the quote. There's no chain to walk, because there's nothing to fall back from. A quote without a customer contact isn't a real quote. Contrast that with the From side, which has to guess between three different people who could plausibly be "the sender." The To side doesn't guess. It just points at the one relationship that has to exist for the record to make sense in the first place.

Most templates on this list work exactly the same way. The interesting ones are the handful that don't, where Odoo explicitly overrides the default, or where nothing is configured at all and some other piece of code has to supply the recipient at send time.

Every Template's To Field, Broken Down

Everything below is stock Odoo 19, pulled directly off a fresh install, no 19 Prince customization. Same template order as the From-field breakdown: customer-facing first, internal/system notifications at the bottom.

TemplateToPlain English
Sales: Send Quotation(Default Recipients ✓)Sends to the quote's own customer contact — Odoo's default recipient for a sale.order. No override configured.
Sales: Order Confirmation(Default Recipients ✓)Sends to the order's own customer contact.
Sales: Payment Done(Default Recipients ✓)Sends to the order's own customer contact.
Sales: Send Proforma(Default Recipients ✓)Sends to the order's own customer contact.
Ecommerce: Cart Recovery(Default Recipients ✓)Sends to the customer tied to the abandoned cart.
Invoice: Sending(Default Recipients ✓)Sends to the invoice's own customer contact.
Credit Note: Sending(Default Recipients ✓)Sends to the credit note's own customer contact.
Self-billing invoice: Sending(Default Recipients ✓)Sends to the invoice's own customer contact.
Self-billing credit note: Sending(Default Recipients ✓)Sends to the credit note's own customer contact.
Payment: Payment Receipt(Default Recipients ✓)Sends to the payment's own customer contact.
Customer Statement(Default Recipients ✓)Sends directly to the customer contact record this statement is about.
Follow Up Report(Default Recipients ✓)Sends directly to the customer contact record this report is about.
Payment Reminder(Default Recipients ✓)Sends directly to the customer contact record being reminded.
Second reminder followup(Default Recipients ✓)Sends directly to the customer contact record being reminded.
Settings: New Portal Sign Up(Default Recipients ✓)Sends to the new portal user's own email.
Settings: New Portal User Invite(Default Recipients ✓) + email_to: {{ object.email_formatted }}Default Recipients wins over the explicit email_to — both resolve to the same address (the invited user's own email), so the email_to value here is effectively unused.
New eInvoices Notificationemail_to: {{ object.incoming_einvoice_notification_email }}Explicit override — sends to whatever address is configured in the company's e-invoice notification setting, not a specific person.
Journal Notification(none configured)No recipient set on the template at all — the calling code must pass the recipient in directly when it triggers this notification.
Bank connection expiration reminderemail_to: {{ object.renewal_contact_email }}Explicit override — sends to whichever email is stored as the renewal contact for that bank connection.
Tax Return Deadlinepartner_to: {{ ctx.get('partner') and ctx['partner'].id }}Recipient comes from context, not the record — whichever partner was passed in when the reminder was triggered.
Tax payment(Default Recipients ✓)Sends to the tax return's own associated contact.
Settings: New User Invite(Default Recipients ✓)Sends to the invited user's own email.
Settings: 2Fa Invitation(Default Recipients ✓)Sends to the user's own email.
Settings: 2Fa New Login(Default Recipients ✓)Sends to the user's own email.
Settings: Unregistered User Reminder(Default Recipients ✓)Sends to the user's own email.
Mail: Install Requestpartner_to: {{ ctx['partner'].id }}Recipient comes from context — whichever partner requested the module install, not a fixed address.
IAP Extract Notification(none configured)No recipient set on the template — passed in directly by the calling code.

Two patterns are worth remembering here. First: when Default Recipients is checked, any hand-written email_to or partner_to value on the same template is dead weight. Odoo won't touch it. Second: the templates showing (none configured) aren't broken, they're just relying on whatever code fires the notification to supply the recipient directly, outside the template entirely. If you ever go looking for "where does this address come from" and the template comes up empty on all three fields, that's your signal to stop reading templates and go read the code that calls them.

— Darren from 19 Prince