[PATCH b4] review: allow a custom Message-Id command for TUI replies

Christian Brauner <[email protected]> Fri, 22 May 2026 12:57:56 +0200
Newsgroups org.kernel.linux.tools
Message-ID <[email protected]>
The review TUI composes replies and sends them directly over SMTP via
send_mail(), bypassing git-send-email and therefore any sendemail-validate
hook that would normally rewrite the Message-Id. Review replies thus always
got a built-in <...@b4> id.

Add an opt-in b4.review-msgid-cmd option: when set, run it and use its
stdout as the Message-Id (angle brackets optional), falling back to the
built-in id when unset or on failure. Wire it into both the review-reply
builder and LoreMessage.make_reply() so follow-up replies are covered too.

Signed-off-by: Christian Brauner (Amutable) <[email protected]>
---
I love b4 review and I'm in the process of making it my default review
tool. 2026 and kernel review is officially better than Github. Didn't
expect to see that day tbh.

All my reviews come with specific message ids and I would like to be
able to continue using them so I would appreciate the ability to define
a message-id generation command in the [b4] .gitconfig section.

I've written the patch for this.

Thanks!
Christian
---
 src/b4/__init__.py       | 28 +++++++++++++++++++++++++++-
 src/b4/review/_review.py |  2 +-
 2 files changed, 28 insertions(+), 2 deletions(-)

diff --git a/src/b4/__init__.py b/src/b4/__init__.py
index 0530fec..ff056e2 100644
--- a/src/b4/__init__.py
+++ b/src/b4/__init__.py
@@ -177,6 +177,8 @@ DEFAULT_CONFIG: ConfigDictT = {
     'review-target-branch': None,
     # Do not patatt-sign outgoing review emails
     'review-no-patatt-sign': None,
+    # Command whose stdout is used as the Message-Id for review-TUI replies
+    'review-msgid-cmd': None,
 }
 
 # This is where we store actual config
@@ -2531,7 +2533,7 @@ class LoreMessage:
         references = LoreMessage.clean_header(self.msg.get('References', '') or '')
         msg['References'] = f'{references} <{self.msgid}>'.strip()
         msg['Date'] = email.utils.formatdate(localtime=True)
-        msg['Message-Id'] = make_msgid(idstring='b4-reply')
+        msg['Message-Id'] = make_msgid_with_cmd(idstring='b4-reply')
         return msg
 
     @staticmethod
@@ -5853,6 +5855,30 @@ def make_msgid(idstring: Optional[str] = None, domain: str = 'b4') -> str:
     return email.utils.make_msgid(idstring=idstring, domain=domain)
 
 
+def make_msgid_with_cmd(idstring: Optional[str] = None, domain: str = 'b4') -> str:
+    """Like make_msgid(), but use b4.review-msgid-cmd's output when set."""
+    config = get_main_config()
+    cmdstr = config.get('review-msgid-cmd')
+    if isinstance(cmdstr, (list, tuple)):
+        cmdstr = cmdstr[0] if cmdstr else None
+    if cmdstr:
+        sp = shlex.shlex(str(cmdstr), posix=True)
+        sp.whitespace_split = True
+        args = [os.path.expanduser(os.path.expandvars(a)) for a in sp]
+        try:
+            out = subprocess.check_output(args, text=True).strip()
+            if out:
+                if not out.startswith('<'):
+                    out = f'<{out}>'
+                return out
+            logger.warning('review-msgid-cmd %s produced no output', args)
+        except (OSError, subprocess.SubprocessError) as ex:
+            logger.warning(
+                'review-msgid-cmd failed (%s); using built-in message-id', ex
+            )
+    return make_msgid(idstring=idstring, domain=domain)
+
+
 def is_maildir(dest: str) -> bool:
     return (
         os.path.isdir(os.path.join(dest, 'new'))
diff --git a/src/b4/review/_review.py b/src/b4/review/_review.py
index 47098c1..f874bb3 100644
--- a/src/b4/review/_review.py
+++ b/src/b4/review/_review.py
@@ -2521,7 +2521,7 @@ def _build_review_email(
     else:
         msg['References'] = f'<{header_info["msgid"]}>'
     msg['Date'] = email.utils.formatdate(localtime=True)
-    msg['Message-Id'] = b4.make_msgid(idstring='b4-review')
+    msg['Message-Id'] = b4.make_msgid_with_cmd(idstring='b4-review')
 
     return msg
 

---
base-commit: d5d981426ead3f490713ef5d2fd1aa3d0f13b005
change-id: 20260522-review-msgid-cmd-49924d64541a