Skip to content

Support repeated mail compose flags - #2271

Open
bubbmon233 wants to merge 5 commits into
larksuite:mainfrom
bubbmon233:feat/e239120
Open

Support repeated mail compose flags#2271
bubbmon233 wants to merge 5 commits into
larksuite:mainfrom
bubbmon233:feat/e239120

Conversation

@bubbmon233

@bubbmon233 bubbmon233 commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

Adds support for passing list-style mail compose flags multiple times while keeping the existing comma-separated forms working.

  • Preserves the order of repeated attachment, remove, and inline inputs before compose requests are built.
  • Keeps recipient parsing compatible with comma-separated values and display names that contain commas.
  • Adds coverage for repeated flags, mixed inline payload forms, and set-* replacement behavior.

Summary by CodeRabbit

  • New Features
    • Mail commands support repeated and comma-separated recipient and attachment options.
    • Inline images accept repeated JSON objects or arrays, with ordered uploads and CID mapping.
    • Template creation and updates support inline images, with plain-text compatibility validation.
    • Display names are safely formatted for international and special-character addresses.
  • Bug Fixes
    • Improved normalization and validation across previews, dry runs, and execution.
    • Duplicate inline image identifiers are now rejected consistently.
  • Documentation
    • Updated guidance for repeatable options, inline formats, parsing, and attachment handling.

@github-actions github-actions Bot added domain/mail PR touches the mail domain size/L Large or sensitive change across domains or core paths labels Aug 10, 2026
@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Mail shortcuts now accept repeatable recipient and attachment flags. Inline images accept repeated JSON objects or arrays. Shared normalization runs during preview, validation, and execution. Template commands upload explicit inline attachments and reject them in plain-text mode.

Changes

Mail input normalization

Layer / File(s) Summary
Normalization helpers and address formatting
shortcuts/mail/address.go, shortcuts/mail/helpers.go, shortcuts/mail/mail_repeatable_flags_test.go
Mailbox display names use RFC 2047 encoding or quoted escaping. Shared helpers normalize repeated values and parse inline objects or arrays. Tests cover ordering, accumulation, duplicate CIDs, invalid JSON, and flag types.

Message shortcut integration

Layer / File(s) Summary
Message shortcut integration
shortcuts/mail/mail_draft_create.go, shortcuts/mail/mail_forward.go, shortcuts/mail/mail_reply.go, shortcuts/mail/mail_reply_all.go, shortcuts/mail/mail_send.go
Message shortcuts use normalized recipient, attachment, exclusion, and inline values during dry-run, validation, and execution. Plain-text templates reject inline images.

Template inline attachment flow

Layer / File(s) Summary
Template inline attachment flow
shortcuts/mail/mail_template_create.go, shortcuts/mail/mail_template_update.go, shortcuts/mail/template_compose.go, shortcuts/mail/mail_template_shortcut_test.go
Template commands normalize and validate inline inputs, include them in dry-run uploads and counts, and pass them to payload construction. Explicit inline files upload before non-inline attachments. Tests cover final template-mode validation.

Mail parameter documentation

Layer / File(s) Summary
Mail parameter documentation
skills/lark-mail/references/lark-mail-*.md
Reference pages document repeated values, comma-separated parsing, inline JSON formats, ordering, and plain-text restrictions.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Sequence Diagram(s)

sequenceDiagram
  participant MailCommand
  participant NormalizationHelpers
  participant TemplatePayloadBuilder
  participant Drive
  participant TemplateAPI
  MailCommand->>NormalizationHelpers: normalize flags and parse inline JSON
  NormalizationHelpers-->>MailCommand: normalized recipients, attachments, and inline specifications
  MailCommand->>TemplatePayloadBuilder: build template payload
  TemplatePayloadBuilder->>Drive: upload inline files in input order
  Drive-->>TemplatePayloadBuilder: uploaded file identifiers
  TemplatePayloadBuilder->>TemplateAPI: submit payload with inline attachments
Loading
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description explains the scope and key changes but omits the required template sections for Changes, Test Plan, and Related Issues. Add the required headings, list the main changes, document verification steps, and state related issues or None.
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: support for repeated mail composition flags.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Aug 10, 2026

Copy link
Copy Markdown

🚀 PR Preview Install Guide

🧰 CLI update

npm i -g https://pkg.pr.new/larksuite/cli/@larksuite/cli@78d5f9365fd6290a9c67501043da6ddb85c745a4

🧩 Skill update

npx skills add bubbmon233/cli#feat/e239120 -y -g

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@shortcuts/mail/address.go`:
- Around line 65-67: In the display-name encoding logic around encodeHeader,
replace the custom encoding path with mime.BEncoding.Encode("UTF-8", name) for
non-ASCII names. Preserve the existing behavior for names that need no encoding,
while ensuring long display names are split into RFC 2047-compliant
encoded-words.

In `@shortcuts/mail/helpers.go`:
- Around line 2382-2390: Update the inline JSON parsing flow around InlineSpec
to inspect the first non-whitespace byte of raw before unmarshalling; accept
only `{` for the object path or `[` for the array path, and return
mailValidationParamError("--inline", ...) for all other values, including null.
Preserve the existing unmarshalling and WithCause handling for valid object and
array inputs.
- Around line 2341-2348: Update normalizeInlineFlagValues after merging parsed
entries into all to validate that every CID is unique across the entire slice,
returning an error on duplicates before generating normalized JSON. Preserve the
existing parseInlineSpecs error handling and allow entries without a CID
according to current behavior.

In `@shortcuts/mail/mail_draft_create.go`:
- Around line 141-144: The template application flow must reject explicit inline
attachments when the selected template sets plain-text mode, rather than
silently omitting them. In shortcuts/mail/mail_draft_create.go lines 141-144,
after applyTemplate, return an error when input.Inline is non-empty and
input.PlainText is true; in shortcuts/mail/mail_send.go lines 144-147, apply the
equivalent check for inlineFlag and plainText. Add regression tests covering
both flows.

In `@shortcuts/mail/mail_template_update.go`:
- Around line 111-121: The inline/plain-text conflict is validated before
patch-file overrides are applied, so it must be checked against the final
template state. In shortcuts/mail/mail_template_update.go lines 111-121, remove
this conflict check from Validate; in lines 185-199, after
applyTemplatePatchFile, reject inline usage only when tpl.IsPlainTextMode is
true. Add regression tests covering both patch override directions: patching to
HTML permits inline, and patching to plain text rejects it.

In `@skills/lark-mail/references/lark-mail-template-update.md`:
- Line 74: Update the --inline option description in the template-update
documentation to state that inline attachments are rejected when the final
template uses plain-text mode, while preserving the existing ordering and
repeatable-argument behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8ce59ba9-d80a-4be0-b87e-c5b226b7a44c

📥 Commits

Reviewing files that changed from the base of the PR and between 70ca6e2 and 4f03321.

📒 Files selected for processing (18)
  • shortcuts/mail/address.go
  • shortcuts/mail/helpers.go
  • shortcuts/mail/mail_draft_create.go
  • shortcuts/mail/mail_forward.go
  • shortcuts/mail/mail_repeatable_flags_test.go
  • shortcuts/mail/mail_reply.go
  • shortcuts/mail/mail_reply_all.go
  • shortcuts/mail/mail_send.go
  • shortcuts/mail/mail_template_create.go
  • shortcuts/mail/mail_template_update.go
  • shortcuts/mail/template_compose.go
  • skills/lark-mail/references/lark-mail-draft-create.md
  • skills/lark-mail/references/lark-mail-forward.md
  • skills/lark-mail/references/lark-mail-reply-all.md
  • skills/lark-mail/references/lark-mail-reply.md
  • skills/lark-mail/references/lark-mail-send.md
  • skills/lark-mail/references/lark-mail-template-create.md
  • skills/lark-mail/references/lark-mail-template-update.md

Comment thread shortcuts/mail/address.go
Comment thread shortcuts/mail/helpers.go
Comment thread shortcuts/mail/helpers.go Outdated
Comment thread shortcuts/mail/mail_draft_create.go
Comment thread shortcuts/mail/mail_template_update.go Outdated
Comment thread skills/lark-mail/references/lark-mail-template-update.md Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@shortcuts/mail/mail_repeatable_flags_test.go`:
- Around line 98-106: Replace message-only assertions in
TestNormalizeRepeatedInlineFlagsRejectsDuplicateCID and the related tests in
shortcuts/mail/mail_repeatable_flags_test.go lines 98-106 and 108-117, and
shortcuts/mail/mail_template_shortcut_test.go lines 1154-1187, 1189-1220, and
1222-1258, with typed validation checks. Use errors.As to inspect
*errs.ValidationError, including Param set to --inline, and use errs.ProblemOf
only for problem-level metadata; assert the expected duplicate-CID,
non-object/non-array, send, draft-create, and final patched plain-text
validation categories and conflicts. Do not rely on err.Error() text alone, and
preserve the stated absence of wrapped causes for these local validation
branches.

In `@shortcuts/mail/mail_template_shortcut_test.go`:
- Around line 1285-1317: Strengthen the MailTemplateUpdate test around
runMountedMailShortcut by retaining the upload POST stub and asserting it
received a request, then inspect putStub.CapturedBody to verify the inline
attachment fields contain CID “hero” and the uploaded token “file_logo”. Keep
the existing HTML-mode assertion and ensure the test directly covers both upload
and attachment assembly.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: fe6f4566-a5a8-4ef9-970b-04b5d2592554

📥 Commits

Reviewing files that changed from the base of the PR and between 4f03321 and 524e217.

📒 Files selected for processing (8)
  • shortcuts/mail/address.go
  • shortcuts/mail/helpers.go
  • shortcuts/mail/mail_draft_create.go
  • shortcuts/mail/mail_repeatable_flags_test.go
  • shortcuts/mail/mail_send.go
  • shortcuts/mail/mail_template_shortcut_test.go
  • shortcuts/mail/mail_template_update.go
  • skills/lark-mail/references/lark-mail-template-update.md
🚧 Files skipped from review as they are similar to previous changes (6)
  • shortcuts/mail/address.go
  • shortcuts/mail/helpers.go
  • shortcuts/mail/mail_draft_create.go
  • skills/lark-mail/references/lark-mail-template-update.md
  • shortcuts/mail/mail_template_update.go
  • shortcuts/mail/mail_send.go

Comment thread shortcuts/mail/mail_repeatable_flags_test.go Outdated
Comment thread shortcuts/mail/mail_template_shortcut_test.go Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@shortcuts/mail/mail_repeatable_flags_test.go`:
- Around line 123-134: Update assertInlineValidationError to assert that
ve.Category equals errs.CategoryValidation alongside the existing subtype and
parameter checks, preserving the helper’s typed metadata validation.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 68435373-6e90-463a-b069-0489b89d4572

📥 Commits

Reviewing files that changed from the base of the PR and between 524e217 and 6690f5f.

📒 Files selected for processing (2)
  • shortcuts/mail/mail_repeatable_flags_test.go
  • shortcuts/mail/mail_template_shortcut_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • shortcuts/mail/mail_template_shortcut_test.go

Comment thread shortcuts/mail/mail_repeatable_flags_test.go
@bubbmon233

Copy link
Copy Markdown
Collaborator Author

[P2 correctness] 非 ASCII display-name 会被内部归一化提前 MIME 编码

锚点:

parts = append(parts, m.String())

这里不能用 Mailbox.String() 做重复收件人 flag 的内部归一化。Mailbox.String() 会把非 ASCII display-name 先转成 RFC 2047 encoded-word;后续发送路径的 parseNetAddrs 和模板路径的 renderTemplateAddresses 又把这个 encoded-word 当普通 name 解析。复现输入 --to '测试用户 <a@example.com>' 时,最终 EML 会输出 "=?UTF-8?...?=" <a@example.com>,模板默认收件人的 name 也会保存为编码串,而不是原始中文显示名。

建议归一化阶段只保护逗号边界和 ASCII quote,保留原始 Unicode name 给最终 EML 头编码/模板 JSON 渲染;补一条 normalizeRecipientFlagValues -> parseNetAddrs/renderTemplateAddresses 的非 ASCII display-name 回归测试。

@bubbmon233

Copy link
Copy Markdown
Collaborator Author

[P2 correctness] 多逗号 display-name 会被拆成额外收件人

锚点:

if !strings.Contains(part, "@") && i+1 < len(parts) && strings.Contains(parts[i+1], "<") {

这里只在当前片段无 @ 且下一片段含 < 时开始合并,所以未加引号但包含多个逗号的 display-name 会漏掉前面的片段。例如 --to 'ACME, Inc., Billing <billing@example.com>' 被拆成 ACME"Inc., Billing" <billing@example.com>ParseMailbox("ACME") 会把它当一个裸地址保留,导致多出无效收件人或后端拒绝。技术方案要求 display-name 中的逗号不能被拆坏,这个边界还没有覆盖。

建议从当前位置向后持续合并,直到形成完整 <...> 地址;无法组成合法 mailbox 的残片不要静默作为收件人,应该返回参数错误。

@bubbmon233

Copy link
Copy Markdown
Collaborator Author

[P2 correctness] --inline 的 CID 只在去重时归一化,后续校验和构建仍使用原值

锚点:

buf, err := json.Marshal(all)

validateUniqueInlineCIDsnormalizeInlineCID 判断重复,但这里 marshal 的仍是原始 all。这会让 {"cid":"cid:hero"} / {"cid":"<hero>"} 在去重时按 hero 看待,后续 validateInlineCIDsAddFileInline 却继续拿原值:正文 cid:hero 会被判 missing,模板创建/更新也会保存正文引用不到的 inline attachment。

建议在 normalizeInlineFlagValues 中把 all[i].CID 写回 bare CID 后再校验和 marshal,或直接拒绝带 cid: 前缀/尖括号的输入;同时补覆盖 cid:hero/<hero> 的回归测试。

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
shortcuts/mail/mail_template_shortcut_test.go (1)

1154-1200: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Assert that plain-text compose omits explicit inline attachments.

Both tests only assert a successful draft ID. An implementation that still embeds logo.png as an inline MIME part with CID hero can make the same POST request and pass.

  • shortcuts/mail/mail_template_shortcut_test.go#L1154-L1200: Retain the draft POST stub and inspect the raw EML. Assert that it has no Content-ID: <hero> inline part.
  • shortcuts/mail/mail_template_shortcut_test.go#L1202-L1247: Retain the draft POST stub and assert the same absence for +draft-create.

As per coding guidelines, “Every behavior change requires a nearby regression test that fails when the implementation is reverted; tests should assert fields, requests, typed errors, or side effects directly.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@shortcuts/mail/mail_template_shortcut_test.go` around lines 1154 - 1200,
Strengthen TestMailSend_TemplatePlainTextIgnoresExplicitInline by inspecting the
raw EML from the retained draft POST stub and asserting it contains no inline
MIME part with Content-ID <hero>. Apply the same assertion to
shortcuts/mail/mail_template_shortcut_test.go lines 1202-1247 for the
+draft-create test; both sites require direct regression-test updates beyond
checking only the draft ID.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@shortcuts/mail/mail_repeatable_flags_test.go`:
- Around line 100-115: Update normalizeInlineFlagValues and the parsed
inline-spec handling to canonicalize every CID by removing surrounding angle
brackets before marshaling, while preserving duplicate-CID compatibility. Extend
TestNormalizeRepeatedInlineFlagsAllowsDuplicateCIDForCompatibility to inspect
both normalized entries and assert their CID fields are the expected bare,
canonical value rather than only checking the entry count.

---

Outside diff comments:
In `@shortcuts/mail/mail_template_shortcut_test.go`:
- Around line 1154-1200: Strengthen
TestMailSend_TemplatePlainTextIgnoresExplicitInline by inspecting the raw EML
from the retained draft POST stub and asserting it contains no inline MIME part
with Content-ID <hero>. Apply the same assertion to
shortcuts/mail/mail_template_shortcut_test.go lines 1202-1247 for the
+draft-create test; both sites require direct regression-test updates beyond
checking only the draft ID.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e91de36b-2fd5-4d23-af58-76b6c82e4e56

📥 Commits

Reviewing files that changed from the base of the PR and between 3c819de and a2a1f61.

📒 Files selected for processing (12)
  • shortcuts/mail/helpers.go
  • shortcuts/mail/mail_draft_create.go
  • shortcuts/mail/mail_repeatable_flags_test.go
  • shortcuts/mail/mail_send.go
  • shortcuts/mail/mail_template_shortcut_test.go
  • skills/lark-mail/references/lark-mail-draft-create.md
  • skills/lark-mail/references/lark-mail-forward.md
  • skills/lark-mail/references/lark-mail-reply-all.md
  • skills/lark-mail/references/lark-mail-reply.md
  • skills/lark-mail/references/lark-mail-send.md
  • skills/lark-mail/references/lark-mail-template-create.md
  • skills/lark-mail/references/lark-mail-template-update.md
💤 Files with no reviewable changes (2)
  • shortcuts/mail/mail_send.go
  • shortcuts/mail/mail_draft_create.go
🚧 Files skipped from review as they are similar to previous changes (8)
  • skills/lark-mail/references/lark-mail-template-create.md
  • skills/lark-mail/references/lark-mail-draft-create.md
  • skills/lark-mail/references/lark-mail-forward.md
  • skills/lark-mail/references/lark-mail-reply-all.md
  • skills/lark-mail/references/lark-mail-reply.md
  • skills/lark-mail/references/lark-mail-template-update.md
  • skills/lark-mail/references/lark-mail-send.md
  • shortcuts/mail/helpers.go

Comment on lines +100 to +115
func TestNormalizeRepeatedInlineFlagsAllowsDuplicateCIDForCompatibility(t *testing.T) {
raw, err := normalizeInlineFlagValues([]string{
`{"cid":"Logo","file_path":"./a.png"}`,
`[{"cid":"<logo>","file_path":"./b.png"}]`,
})
if err != nil {
t.Fatalf("expected duplicate cid compatibility, got %v", err)
}
specs, err := parseInlineSpecs(raw)
if err != nil {
t.Fatalf("parseInlineSpecs(%q) error = %v", raw, err)
}
if len(specs) != 2 {
t.Fatalf("inline specs = %#v, want 2 entries", specs)
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Normalize parsed CIDs and assert canonical output.

normalizeInlineFlagValues marshals the parseInlineSpecs results. The supplied parser only checks that CID is non-empty. It leaves <logo> unchanged in normalized JSON.

Normalize each CID to its bare form before marshaling. Assert the expected normalized CID fields in this test. The entry-count assertion does not detect an inline attachment that uses <logo> while the HTML references cid:logo.

As per coding guidelines, “Every behavior change requires a nearby regression test that fails when the implementation is reverted; tests should assert fields, requests, typed errors, or side effects directly.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@shortcuts/mail/mail_repeatable_flags_test.go` around lines 100 - 115, Update
normalizeInlineFlagValues and the parsed inline-spec handling to canonicalize
every CID by removing surrounding angle brackets before marshaling, while
preserving duplicate-CID compatibility. Extend
TestNormalizeRepeatedInlineFlagsAllowsDuplicateCIDForCompatibility to inspect
both normalized entries and assert their CID fields are the expected bare,
canonical value rather than only checking the entry count.

Source: Coding guidelines

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

domain/mail PR touches the mail domain size/L Large or sensitive change across domains or core paths

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant