Post to the chatter
odoo_message_postPost a message to the chatter of an Odoo record: res_model plus res_id for ONE record, or res_ids to put the SAME message on a whole selection — one call, never a loop of res_id. The parameters are documented in the schema; what follows is what causes damage when it is ignored.
DEFAULT IS AN INTERNAL NOTE. A customer-facing mail.mt_comment, or an external partner in partner_ids, only goes through when the workspace messaging mode is 'all'.
MENTIONS: write @partner:<id> in body exactly where the name belongs — always a res.partner id, and also listed in partner_ids. Only mention someone the user named explicitly; if you inferred the recipient, ask before notifying them. Then read notified (id AND name): res.users and res.partner ids collide, so a wrong id notifies a real but different person.
THE LIST FORM IS THE PLAIN NOTE: attachments, mt_comment, partner_ids and mentions each fire once PER RECORD, so they are refused over res_ids — post the note on the list, and post once on a single res_id if somebody has to be told.
NOTHING HERE CAN BE UN-POSTED. With res_ids the answer carries posted, failed, not_attempted and partial: never report the whole selection as done, and retry ONLY the ids that did not take it, or the note lands twice on the rest.
BODY (unless body_is_html=true, which goes as is): Html fields take markdown, converted the Odoo way: - [ ]/- [x] checklists, pipe tables, ##/### sections, --- separators. No inline style, invented classes or invented image URLs.
Tool call template
Replace each placeholder with a value matching the input schema. Only required parameters are included; add optional parameters as needed.
{
"id": 1,
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"arguments": {
"res_model": "<res_model>"
},
"name": "odoo_message_post"
}
}Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| body | No | Message body. Markdown by default (converted to HTML); raw HTML if body_is_html=true. Write `@partner:<id>` where a mention should appear. | |
| res_id | No | ID of the record to post on. Use this OR `res_ids`, not both. | |
| res_ids | No | IDs of the records to post the SAME message on (up to 200). Use this OR `res_id`, not both. One call for the whole list — do not loop `res_id`. | |
| subtype | No | 'mail.mt_note' (default) = internal note. 'mail.mt_comment' = customer-facing message that notifies the record's followers — only allowed when the workspace messaging mode is 'all'. | |
| res_model | Yes | Technical model name of the record (e.g. 'helpdesk.ticket', 'project.task'). | |
| partner_ids | No | Optional **res.partner** IDs to notify — never a res.users ID (the two collide, so the wrong one notifies a different person; take the `partner_id` field of the user you looked up). These IDs are what sends the notification; to also show the person's name in the message, write `@partner:<id>` in `body` where the name belongs. In 'internal' mode only partners backing an internal user are kept (externals dropped, reported back); in 'all' mode external partners are honored. An ID that resolves to no partner is not notified and comes back in `unknown_partner_ids`. | |
| upload_refs | No | Files from your disk to attach to the message (a screenshot, a CSV, a PDF): upload each one with `file_upload_url` and pass the 'tuqui-upload:<id>' reference it returns, once its curl succeeded. | |
| body_is_html | No | Set true if `body` is already HTML. Default false (body is markdown). | |
| odoo_attachment_ids | No | IDs of `ir.attachment` records already in Odoo, to attach a COPY of them to this message (e.g. the recording of a call, onto the lead). The original stays where it is. Get the ids with `odoo_attachment_content` (res_model + res_id lists a record's attachments); never guess them. Works over MCP too, no conversation needed. |