Skip to content

feat(mail): auto-attach default signature on send/reply/forward#1415

Merged
xzcong0820 merged 10 commits into
larksuite:mainfrom
xzcong0820:feat/6dd7472
Jun 15, 2026
Merged

feat(mail): auto-attach default signature on send/reply/forward#1415
xzcong0820 merged 10 commits into
larksuite:mainfrom
xzcong0820:feat/6dd7472

Conversation

@xzcong0820

@xzcong0820 xzcong0820 commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

Generated by the harness-coding skill.

  • Branch: feat/6dd7472
  • Target: main

Sprints

ID Title Status Commit
S1 lark-cli auto-attach default signature on send/reply/forward passed dc674af
S2 Synthesize transport contract for larksuite/cli passed

This MR was created autonomously. Quality gates were enforced by the repo's own pre-commit hooks.

Summary by CodeRabbit

  • New Features

    • Added a --no-signature option to mail commands (draft-create, send, reply, reply-all, forward) to skip default signatures.
    • Plain-text mode now appends a plain-text rendition of HTML signatures automatically.
    • Signature selection now consistently respects the finalized sender and auto-resolves defaults when not specified.
  • Documentation

    • Updated mail command docs to reflect --no-signature and its mutual-exclusion with --signature-id, plus plain-text behavior.

@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d4114865-3910-4068-a41b-df66cfc4544f

📥 Commits

Reviewing files that changed from the base of the PR and between dc674af and 64abb76.

📒 Files selected for processing (1)
  • shortcuts/mail/signature_compose_test.go

📝 Walkthrough

Walkthrough

A shared --no-signature flag, typed validation, auto-resolve helpers, and plain-text signature injection are added and applied to draft-create, forward, reply, reply-all, and send shortcuts; tests and CLI docs are updated accordingly.

Changes

Mail signature flag and composition refactoring

Layer / File(s) Summary
Core signature utilities and helpers
shortcuts/mail/signature_compose.go, shortcuts/mail/signature/provider.go, shortcuts/mail/draft/htmltext.go, shortcuts/mail/signature_compose_test.go
Shared --no-signature flag and validateNoSignatureConflict enforce mutual exclusion with --signature-id. New autoResolveSignatureID resolves defaults for reply vs. send/draft, and injectPlainTextSignature appends HTML-rendered signatures to plain-text bodies. DefaultSendID and DefaultReplyID helpers return defaults by case-insensitive email match. PlainTextFromHTML exports HTML-to-plain-text conversion. Tests verify conflict and no-conflict cases.
Draft-create shortcut: --no-signature flag and signature refactoring
shortcuts/mail/mail_draft_create.go, shortcuts/mail/mail_draft_create_test.go
--no-signature added; validation switches to validateNoSignatureConflict. Signature resolution moved after senderEmail finalized; --no-signature clears signatureID, otherwise it is auto-resolved. buildRawEMLForDraftCreate accepts senderEmailHint to avoid re-resolution. Plain-text drafts inject signature via injectPlainTextSignature. Tests updated for new argument.
Reply, forward, reply-all, and send shortcuts: --no-signature flag and signature refactoring
shortcuts/mail/mail_forward.go, shortcuts/mail/mail_reply.go, shortcuts/mail/mail_reply_all.go, shortcuts/mail/mail_send.go
Each shortcut adds --no-signature; validation uses validateNoSignatureConflict. Signature resolution now occurs after final sender determination, honors --no-signature, auto-resolves when unspecified, and calls resolveSignature with finalized sender. Plain-text composition injects signatures via injectPlainTextSignature before quoting/composing body.
Skill documentation for all mail compose commands
skills/lark-mail/references/lark-mail-draft-create.md, skills/lark-mail/references/lark-mail-forward.md, skills/lark-mail/references/lark-mail-reply.md, skills/lark-mail/references/lark-mail-reply-all.md, skills/lark-mail/references/lark-mail-send.md
--plain-text clarified to note plain-text signature injection and inline-image handling. New --no-signature documented with mutual exclusion to --signature-id. --signature-id is no longer documented as conflicting with --plain-text.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • larksuite/cli#205: Overlaps on buildRawEMLForDraftCreate changes and inline-image/inline CID handling.
  • larksuite/cli#1250: Related edits to signature_compose.go validation/refactor logic.
  • larksuite/cli#537: Related to signature placement and compose pipeline adjustments.

Suggested labels

feature

Suggested reviewers

  • infeng
  • chanthuang
  • haidaodashushu

Poem

🐰 A small flag hops into the mail,
“No signature” — skip the fancy tail.
When plain text calls for a tidy line,
HTML sigs convert and hop in fine.
Rabbity cheers for cleaner compose time!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description lacks the required template structure. It is missing Summary, Changes, Test Plan, and Related Issues sections specified in the repository template. Restructure the description to follow the template: add a Summary section, itemize main Changes, include a Test Plan checklist, and specify Related Issues.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: automatic attachment of default signatures during send/reply/forward operations, which aligns with the changeset's primary objective.
Docstring Coverage ✅ Passed Docstring coverage is 83.33% which is sufficient. The required threshold is 80.00%.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 and usage tips.

@github-actions github-actions Bot added domain/mail PR touches the mail domain size/M Single-domain feat or fix with limited business impact labels Jun 11, 2026

@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

Caution

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

⚠️ Outside diff range comments (2)
shortcuts/mail/mail_draft_create_test.go (2)

274-296: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Add coverage for the new plain-text signature path.

This test still only proves that CID resolution is skipped. The changed branch now also runs injectPlainTextSignature(...), so a regression in plain-text signature rendering would go unnoticed. Add a variant with a non-nil sigResult and assert the emitted text body; a no-signature variant would lock down the flag behavior too.

As per coding guidelines, every behavior change needs a test alongside the change.

🤖 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_draft_create_test.go` around lines 274 - 296, The test
TestBuildRawEMLForDraftCreate_PlainTextSkipsResolve only checks that CID
resolution is skipped but doesn't exercise the new plain-text signature path;
update the test (or add a new variant) to call buildRawEMLForDraftCreate with a
non-nil sigResult so injectPlainTextSignature(...) runs, then decode the
produced raw EML and assert the emitted plain-text body contains the expected
signature text; also add a complementary no-signature variant (sigResult nil) to
lock down flag behavior and ensure both branches of injectPlainTextSignature are
covered.

Source: Coding guidelines


127-133: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Assert typed error contracts here, not message fragments.

These negative tests will still pass if the error category/subtype/param is downgraded or the cause chain is lost, because they only match substrings. Please switch them to typed assertions via errs.ProblemOf(err), and use errors.As with *errs.ValidationError when you need to verify Param.

As per coding guidelines, error-path tests must assert typed metadata and cause preservation, and based on learnings errs.ProblemOf does not expose Param directly.

Also applies to: 148-154, 169-175

🤖 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_draft_create_test.go` around lines 127 - 133, Replace the
substring-based assertions with typed error checks: call errs.ProblemOf(err) and
assert the returned problem is non-nil, then use errors.As(err, &ve) to cast
into *errs.ValidationError (or the appropriate error type) to assert the
specific Param or subtype; apply this to the failing call to
buildRawEMLForDraftCreate (and the similar cases around the other tests
indicated) so the test verifies the typed error and Param rather than just
matching "25 MB" or "large attachment" in the error message.

Sources: Coding guidelines, Learnings

🧹 Nitpick comments (1)
skills/lark-mail/references/lark-mail-draft-create.md (1)

52-52: ⚡ Quick win

Consider removing implementation detail PlainTextFromHTML from user-facing documentation.

The parameter description exposes the internal function name PlainTextFromHTML. User documentation typically describes behavior without referencing code internals. Consider revising to:

"纯文本模式下也会自动追加纯文本签名(HTML 签名自动转换为纯文本,内联图片丢弃)"

This applies to all five command reference files at the same line describing --plain-text.

🤖 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 `@skills/lark-mail/references/lark-mail-draft-create.md` at line 52, Update the
user-facing docs to remove the internal function name PlainTextFromHTML from the
`--plain-text` parameter description: replace the fragment
"纯文本模式下也会自动追加纯文本签名(HTML 签名经 `PlainTextFromHTML` 转换,内联图片丢弃)" with
"纯文本模式下也会自动追加纯文本签名(HTML 签名自动转换为纯文本,内联图片丢弃)" in the `--plain-text` descriptions
across all five command reference files so the behavior is described without
exposing implementation details.
🤖 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/signature_compose_test.go`:
- Around line 10-19: Update TestValidateNoSignatureConflictTypedError to assert
structured error metadata instead of only message text: call
validateNoSignatureConflict(true, "sig_123") then use errs.ProblemOf on the
returned error to assert the validation category/subtype produced by
errs.NewValidationError, and use errors.As to cast the error to the concrete
validation error type (e.g., *errs.ValidationError) and assert its Param field
equals the parameter name used by validateNoSignatureConflict (the signature id
param). Keep existing non-nil assertion but replace the message-only checks with
these structured assertions referencing validateNoSignatureConflict,
errs.NewValidationError, errs.ProblemOf and errors.As.

In `@shortcuts/mail/signature_compose.go`:
- Around line 36-45: In validateNoSignatureConflict replace the legacy
output.ErrValidation return with errs.NewValidationError and supply structured
metadata: call errs.NewValidationError with a category like "validation", a
subtype such as "mutually-exclusive", the param identifying the conflicting
flags (e.g. "--no-signature/--signature-id"), and the human message
"--no-signature and --signature-id are mutually exclusive"; also add the errs
import if missing and remove the output package usage for this error.

---

Outside diff comments:
In `@shortcuts/mail/mail_draft_create_test.go`:
- Around line 274-296: The test
TestBuildRawEMLForDraftCreate_PlainTextSkipsResolve only checks that CID
resolution is skipped but doesn't exercise the new plain-text signature path;
update the test (or add a new variant) to call buildRawEMLForDraftCreate with a
non-nil sigResult so injectPlainTextSignature(...) runs, then decode the
produced raw EML and assert the emitted plain-text body contains the expected
signature text; also add a complementary no-signature variant (sigResult nil) to
lock down flag behavior and ensure both branches of injectPlainTextSignature are
covered.
- Around line 127-133: Replace the substring-based assertions with typed error
checks: call errs.ProblemOf(err) and assert the returned problem is non-nil,
then use errors.As(err, &ve) to cast into *errs.ValidationError (or the
appropriate error type) to assert the specific Param or subtype; apply this to
the failing call to buildRawEMLForDraftCreate (and the similar cases around the
other tests indicated) so the test verifies the typed error and Param rather
than just matching "25 MB" or "large attachment" in the error message.

---

Nitpick comments:
In `@skills/lark-mail/references/lark-mail-draft-create.md`:
- Line 52: Update the user-facing docs to remove the internal function name
PlainTextFromHTML from the `--plain-text` parameter description: replace the
fragment "纯文本模式下也会自动追加纯文本签名(HTML 签名经 `PlainTextFromHTML` 转换,内联图片丢弃)" with
"纯文本模式下也会自动追加纯文本签名(HTML 签名自动转换为纯文本,内联图片丢弃)" in the `--plain-text` descriptions
across all five command reference files so the behavior is described without
exposing implementation details.
🪄 Autofix (Beta)

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

Run ID: 2ee32e1b-c7ae-4d7a-9207-a1813039aa3e

📥 Commits

Reviewing files that changed from the base of the PR and between c11cf3b and dc674af.

📒 Files selected for processing (15)
  • shortcuts/mail/draft/htmltext.go
  • shortcuts/mail/mail_draft_create.go
  • shortcuts/mail/mail_draft_create_test.go
  • shortcuts/mail/mail_forward.go
  • shortcuts/mail/mail_reply.go
  • shortcuts/mail/mail_reply_all.go
  • shortcuts/mail/mail_send.go
  • shortcuts/mail/signature/provider.go
  • shortcuts/mail/signature_compose.go
  • shortcuts/mail/signature_compose_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

Comment thread shortcuts/mail/signature_compose_test.go
Comment thread shortcuts/mail/signature_compose.go
Comment thread shortcuts/mail/mail_send.go
Comment thread shortcuts/mail/signature_compose.go
Comment thread shortcuts/mail/mail_draft_create_test.go Outdated
Comment thread shortcuts/mail/signature_compose_test.go
@xzcong0820

Copy link
Copy Markdown
Collaborator Author

🤖 AI Review | CR 汇总 | 有风险(2 个 P2,2 个 P3)

增量审查:基于已有 resolved/withdrawn 评论,本次新增 4 条评论。主要风险是 plain-text 签名仍下载图片导致发信失败、自动默认签名 stale ID 阻断发信;另有 gofmt 门禁和核心行为测试覆盖缺口。

- Add exported PlainTextFromHTML wrapper in draft/htmltext.go
- Add DefaultSendID/DefaultReplyID in signature/provider.go
- Add noSignatureFlag, autoResolveSignatureID, validateNoSignatureConflict,
  injectPlainTextSignature in signature_compose.go; remove validateSignatureWithPlainText
- mail_send, mail_draft_create: add --no-signature flag, auto-resolve default
  signature when no --signature-id given, inject plain-text sig in plain-text branch
- mail_reply, mail_reply_all, mail_forward: same flag/validate changes + timing fix
  (resolveSignature moved to after senderEmail is finalized)
- Update 5 reference docs: add --no-signature row, update --plain-text and
  --signature-id descriptions

sprint: S1
- Add senderEmailHint param to buildRawEMLForDraftCreate to avoid
  duplicate profile API calls when Execute already resolved the sender
- Update signature_compose_test: replace deleted validateSignatureWithPlainText
  test with validateNoSignatureConflict tests
- Update mail_draft_create_test: add new senderEmailHint arg to all
  buildRawEMLForDraftCreate call sites

sprint: S1
- Strip errs-typed error assertions from signature_compose_test.go
  (errs package not present on origin/main base; plain fmt.Errorf used)
- Keep only validateNoSignatureConflict tests which don't need errs
- Fix 4-return buildRawEMLForDraftCreate test calls to use 2-return form

sprint: S1
@github-actions

github-actions Bot commented Jun 12, 2026

Copy link
Copy Markdown

🚀 PR Preview Install Guide

🧰 CLI update

npm i -g https://pkg.pr.new/larksuite/cli/@larksuite/cli@57cd96a3d4519ea51d02270ae48f233a6216d79d

🧩 Skill update

npx skills add xzcong0820/larksuite-cli#feat/6dd7472 -y -g

…efault signature

- Add `userExplicit` and `includeImages` params to `resolveSignature`.
  Plain-text paths now pass `includeImages=false`, avoiding unnecessary
  HTTP downloads for images that are discarded in plain-text mode (also
  prevents send failures from expired pre-signed URLs / CDN errors).
- When `userExplicit=false` (auto-resolved default) and `signature.Get`
  returns a ValidationError (stale ID pointing to deleted signature),
  degrade gracefully: emit a stderr warning and continue without signature
  instead of aborting the send/reply/forward operation.
- Fix gofmt: remove trailing blank line in signature_compose.go.

Change-Type: ci-fix
@codecov

codecov Bot commented Jun 12, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 63.71681% with 41 lines in your changes missing coverage. Please review.
✅ Project coverage is 73.38%. Comparing base (2a7e9c7) to head (57cd96a).
⚠️ Report is 18 commits behind head on main.

Files with missing lines Patch % Lines
shortcuts/mail/signature_compose.go 65.78% 13 Missing ⚠️
shortcuts/mail/mail_forward.go 50.00% 2 Missing and 4 partials ⚠️
shortcuts/mail/mail_reply.go 50.00% 2 Missing and 4 partials ⚠️
shortcuts/mail/mail_reply_all.go 50.00% 2 Missing and 4 partials ⚠️
shortcuts/mail/mail_send.go 44.44% 2 Missing and 3 partials ⚠️
shortcuts/mail/mail_draft_create.go 73.33% 1 Missing and 3 partials ⚠️
shortcuts/mail/mail_draft_edit.go 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1415      +/-   ##
==========================================
+ Coverage   72.83%   73.38%   +0.55%     
==========================================
  Files         732      750      +18     
  Lines       69140    69353     +213     
==========================================
+ Hits        50356    50895     +539     
+ Misses      15003    14709     -294     
+ Partials     3781     3749      -32     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

…verage tests

- Replace forbidden output.ErrValidation with mailValidationParamError
  (satisfies forbidigo lint rule [errs-typed-only])
- Update TestValidateNoSignatureConflictTypedError to assert *errs.ValidationError
  instead of *output.ExitError
- Add unit tests for contentTypeFromFilename, signatureCIDs, injectSignatureIntoBody,
  and addSignatureImagesToBuilder (pure-function coverage)

Change-Type: ci-fix
…Signature

- TestAutoResolveSignatureID_APIFailureReturnsEmpty: API error degrades to ""
- TestAutoResolveSignatureID_NoDefaultConfigured: no usage match returns ""
- TestAutoResolveSignatureID_ReturnsSendID/ReturnsReplyID: correct default ID returned
- TestResolveSignature_EmptyIDReturnsNil: empty signatureID short-circuits to nil
- TestResolveSignature_StaleIDAutoDegradesGracefully: userExplicit=false + not-found
  yields nil/nil (no error) matching the graceful degradation path
- TestResolveSignature_StaleIDUserExplicitFails: userExplicit=true propagates the
  ValidationError so caller can surface "signature not found" to the user

Change-Type: ci-fix
…PlainTextFromHTML

- shortcuts/mail/signature/provider_test.go: 10 tests covering DefaultSendID
  and DefaultReplyID (exact match, case-insensitive, no-match, ID=0, nil usages)
- shortcuts/mail/draft/htmltext_test.go: TestPlainTextFromHTMLExported covering
  the exported PlainTextFromHTML wrapper

Patch coverage was at 51.32% (target 60%); these tests cover 12 previously
uncovered lines in signature/provider.go and 2 in draft/htmltext.go.

Change-Type: ci-fix

@xzcong0820 xzcong0820 left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

🤖 AI Review | CR 汇总 | 有风险(1 个 P1,2 个 P3)

增量审查:基于已有评论,本次新增 3 条。重点问题是 reply/reply-all/forward 使用纯文本模板时仍可能先下载签名图片,导致本应丢弃的图片网络错误阻断发信。另有 CI 门禁被收窄和过期注释清理建议。

Comment thread shortcuts/mail/mail_reply.go Outdated
Comment thread .github/workflows/ci.yml Outdated
Comment thread shortcuts/mail/signature_compose.go Outdated
…omment

- mail_reply.go: move resolveSignature call to after applyTemplate so the
  final plainText value (potentially set by template IsPlainTextMode) is
  used for the downloadImages decision. Prevents unnecessary image downloads
  when a template forces plain-text mode, avoiding CDN 403/5xx / timeout.
- signature_compose.go: remove stale comment referencing output.ErrValidation;
  the function already uses mailValidationParamError consistently.

Change-Type: ci-fix
恢复在 rebase 冲突解决中误删的 ./extension/... 单测范围
和 errs/ lint guard(go run -C lint . ..)步骤。
本 PR 目标为 mail 签名功能,不应缩小 CI 覆盖范围。
Comment thread shortcuts/mail/mail_forward.go Outdated
Comment thread shortcuts/mail/mail_reply_all.go Outdated
…ard and +reply-all

In +forward and +reply-all, resolveSignature was called before applyTemplate,
meaning it used the pre-template plainText value. A template can override plainText
via IsPlainTextMode, so HTML signature images could be downloaded unnecessarily
for ultimately plain-text mails, causing CDN 403/5xx/timeout failures.

Move resolveSignature to after the template merge block, matching the existing
pattern in +reply. Only signatureID resolution remains before the template merge
(it depends on senderEmail, not on the final plainText).

Change-Type: ci-fix
@github-actions github-actions Bot added size/L Large or sensitive change across domains or core paths and removed size/M Single-domain feat or fix with limited business impact labels Jun 15, 2026
Comment thread shortcuts/mail/mail_send.go

@infeng infeng left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM. No new blocking issues found after the latest updates.

Verified the previous concerns against head 57cd96a3d4519ea51d02270ae48f233a6216d79d: the reply/reply-all/forward signature image download now happens after template plaintext mode is applied, the CI test/lint coverage was restored, and the stale signature comment was removed.

Checks run locally:

  • go test ./shortcuts/mail/...
  • git diff --check 465c789f7c3da7048eb8835f15cfdc9d0760e8d8...HEAD
  • gofmt -l $(git diff --name-only 465c789f7c3da7048eb8835f15cfdc9d0760e8d8...HEAD -- '*.go')
  • python3 scripts/fetch_meta.py && go test ./cmd/schema ./internal/schema

I also ran go test ./cmd/... ./internal/... ./shortcuts/... ./extension/...; it initially failed only because the detached review worktree had not generated API metadata yet, and the affected schema packages passed after running the same scripts/fetch_meta.py step used by CI.

@xzcong0820 xzcong0820 merged commit cf35d1e into larksuite:main Jun 15, 2026
18 checks passed
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.

2 participants