Skip to content

pyvelm v0.13.0

Release date: 2026-05-27

A first-class email composer with templates, multi-recipient To / Cc / Bcc, Reply-To, attachments, and Save as template — launched from any MailThread record's chatter or programmatically.


Highlights

Multi-recipient outgoing mail

mail.message gains recipient_cc, recipient_bcc, and reply_to columns. recipient_email now accepts comma- or semicolon-separated addresses. The SmtpBackend / ConsoleBackend / MailBackend protocol pass cc / bcc / reply-to through, and the dispatcher pre-fetches ir.attachment rows linked to each message and adds them as MIME parts.

record.send_mail(
    template,
    to="ops@acme.example, billing@acme.example",
    cc="watch@acme.example",
    bcc="audit@acme.example",
    reply_to="noreply@acme.example",
    attachment_ids=[att.id],
)

record.notify(
    "Account closed.",
    recipient_email="ops@acme.example",
    cc="manager@acme.example",
)

Base bumped to 0.27.0 (migration 0_26_to_0_27.py is a breadcrumb — schema autogen adds the new nullable columns).

mail_compose module

New bundled module, depends on base + admin. Ships:

  • mail.compose.message — the draft record. Methods: launch(env, *, model, res_id, template_id, recipient_to), action_apply_template(), action_send(), action_save_as_template(name=...).
  • Form + drafts list views and a Workflows → Compose drafts menu entry.
  • HTTP endpoints: /web/mail/compose/launch?model=&res_id=&template_id=, /web/mail/compose/{id}/apply-template, /web/mail/compose/{id}/save-as-template, /web/mail/compose/{id}/send.

Composer behaviour:

  • Auto-resolved To. Scans the bound record for email / email_from / contact_email / work_email / login, then a short list of one-hop Many2one paths (partner_id.email, user_id.email, user_id.login, author_id.login, contact_id.email). First non-empty wins.
  • Templated render. Picking a template + clicking Apply template runs the template's Jinja against object = <record> and overwrites subject + body, leaving the operator free to edit.
  • Save as template. Clones current subject + body into a new mail.template bound to the same model. The composer's current subject is used as the template name (operators rename afterwards).
  • Attachments picker — Many2many to ir.attachment using the existing dialog widget.

Chatter integration

For any record whose model inherits MailThread, the chatter panel's Send email tab now surfaces Open rich composer (templates, Cc/Bcc, attachments) →, which launches the composer in the existing floating PvDialog.

Form header_actions in edit mode

Form-view header action buttons (Apply template, Save as template, Send, etc.) now render in edit mode in addition to display. They hx-include the surrounding form fields, so the action endpoint sees the operator's in-flight edits — no extra Save click required.


Upgrade

pip install -U pyvelm==0.13.0
  1. pyvelm db migrate — applies base 0.26.0 → 0.27.0 (schema autogen adds the three new columns to mail.message).
  2. Apps → Install mail_compose (depends on admin). Or include the module root if you boot loader.load_and_install yourself; BUILTIN_MODULE_ROOTS already covers it.
  3. Apps → Sync any module that already had a chatter-bearing model — the Open rich composer link appears once mail.compose.message is in the registry.
  4. Hard-refresh the browser so the chatter template reload picks up the new link.

If you installed mail_compose 0.1.0 between dev builds, the bump to 0.1.1 drops the NOT NULL on recipient_to via migration 0_1_0_to_0_1_1.py so draft launches stop failing when the auto-resolver finds nothing.


Also in this release

  • mail_compose cross-module menu parent uses the tuple form parent=("admin", "workflows") so the loader resolves to the admin-owned group.
  • MailThread._send_rendered_mail and MailThread.notify now forward cc / bcc / reply_to to the message row, so programmatic posts get the same multi-recipient semantics as the composer.

Docs