Commit Graph

17 Commits

Author SHA1 Message Date
bubbmon233
bbef3cbfb1 feat(mail): HTML lint library + Larksuite-native autofix + lark-mail … (#1019)
* feat(mail): HTML lint library + Larksuite-native autofix + lark-mail skill

为 lark-cli mail 域写信链路引入 HTML lint 能力,提升邮件 HTML 的兼容性、
安全性与 Larksuite-native 格式适配。

lint 库(shortcuts/mail/lint/):
- 四档分类:pass / native-autofix / warn-autofix / error-strip
- 安全规则覆盖 script / iframe / on* 事件处理器 / javascript: 及其它
  危险 URL scheme 等 XSS 向量,未知 scheme 一律删除并归 error
- Larksuite-native 格式自动修复:双层 div 段落、原生多级列表结构、
  灰边引用、Larksuite 蓝链接
- cleaned_html 输出确定性稳定(位置索引派生 data-ol-id),便于
  golden-file 测试与缓存

+lint-html 独立预检 shortcut:
- 只读、不调 API、不建草稿,供 AI / 用户 / CI 在写信前预览 lint 结果

写入路径内置 lint(6 个 compose shortcut):
- +send / +draft-create / +draft-edit / +reply / +reply-all / +forward
  在 emlbuilder 之前强制 lint 净化 HTML
- 默认 envelope 对 lint 改动透明(无 lint 字段),保持小巧供 AI 消费;
  --show-lint-details 显式取证返回 lint_applied[] / original_blocked[]
- --body-file 支持从文件读取 body(32MB 上限),与 --body 互斥

预制 HTML 邮件模板(skills/lark-mail/assets/templates/):
- 资讯周报 / 个人周报 / 团队周报 / 调研报告 / 求职简历 5 套
- 按 Larksuite mail-editor 原生格式编写,含正确的多级列表嵌套结构

lark-mail skill 文档:
- references/lark-mail-html.md:邮件 HTML 写法指南(24 个格式 section
  + 颜色调色盘 + URL scheme + 官方模板套用流程)
- references/lark-mail-lint-html.md:+lint-html 用法
- SKILL.md 顶部 CRITICAL 引导

* fix(mail): remove unused readAttr func and apply gofmt

Drop the unused `readAttr` helper in shortcuts/mail/lint/linter.go
that was flagged by golangci-lint (unused linter). Apply gofmt to
linter.go and rules.go which had minor formatting issues.

* fix(mail): address compose lint and guidance
2026-05-27 22:23:32 +08:00
xzcong0820
88d7ec8ee7 feat(lark-mail): add data integrity and write-confirmation rules (#749)
Adds a new top-level safety section "数据真实性与操作合规" to the
lark-mail skill via the canonical generation pipeline:

  - skill-template/domains/mail.md (source) — adds the section to the
    domain introduction file that gen-skills.py renders into SKILL.md.
  - skills/lark-mail/SKILL.md (regenerated product) — produced by
    `make gen-skills project=mail` from larksuite-cli-registry against
    the modified mail.md source.

Why both files: skills/lark-mail/SKILL.md is auto-generated from
skill-template/domains/mail.md + registry-conf/skill-meta.yaml +
output/from_meta/mail.json. Editing only SKILL.md would be reverted on
the next `make gen-skills` run because SKILL.md has no AUTO-GENERATED
markers and falls into the "no markers -> overwrite whole file" branch
in scripts/gen-skills.py.

The section adds 3 hard constraints on agent behavior:
  - empty result is a valid answer; do not fabricate IDs or placeholders
  - explicit action preview before destructive write operations
    (delete / trash / batch_trash / cancel_scheduled_send / rules.*)
  - reversible modifications (label / read state / folder move) are
    exempt from the preview requirement

Addresses recurring evaluation failures (c03/c04/c06/c09/c14/c19~c24/c40)
where the agent fabricated IDs or auto-executed destructive operations.
2026-05-08 12:13:40 +08:00
chanthuang
dce2beb91c feat(mail): support calendar events in emails (#646)
* feat(ics): add RFC 5545 iCalendar generator and parser

Add shortcuts/mail/ics package:
- builder.go: generates METHOD:REQUEST ICS with VEVENT, ORGANIZER,
  ATTENDEE, DTSTART/DTEND with timezone, UID, and X-LARK-MAIL-DRAFT
- parser.go: parses ICS into ParsedEvent struct, detects IsLarkDraft
- Handles CN quoting, control-char sanitization, email validation,
  line folding per RFC 5545, and TZID edge cases

Change-Id: I01d13285a57a5a4de50891c54d655efa8423c3c1

* feat(mail): support calendar events in emails

- Add --event-summary/start/end/location flags to +send, +reply,
  +reply-all, +forward, +draft-create
- Build ICS and embed as text/calendar in multipart/alternative
- Validate event time range and enforce --event/--send-time mutual
  exclusion (extracted into validateEventSendTimeExclusion)
- CalendarBody() in emlbuilder places ICS correctly
- Exclude BCC from ATTENDEE list

Change-Id: Icf9e49ababebc4e8fcf36760ab613c64938c2744

* feat(mail): X-LARK-MAIL-DRAFT and read-only calendar guard

- ics.Build() writes X-LARK-MAIL-DRAFT:TRUE so Feishu client
  recognizes CLI-created calendar events as editable
- ics.ParseEvent() detects IsLarkDraft field
- +draft-edit rejects --set-event-* on calendars without
  X-LARK-MAIL-DRAFT marker (read-only after send)
- Export FindPartByMediaType from draft package for cross-package use
- Add set_calendar/remove_calendar patch ops with full test coverage

Change-Id: I7d547a4b40880e8d4ee3fecf68864d6ea89e66cd

* feat(mail): forward preserves original calendar ICS

When forwarding an email that contains a calendar event (body_calendar),
pass through the original ICS bytes as text/calendar part if no new
--event-* flags are specified.

Change-Id: I67d2e82604eaf969cee8c7e0bedcf32198d12d57

* docs(mail): document calendar invitation feature

- Add --event-* params to +send, +reply, +reply-all, +forward,
  +draft-create, +draft-edit reference docs
- Add calendar_event output section to +message reference
- Add calendar invitation workflow to skill-template/domains/mail.md
- Regenerate SKILL.md via gen-skills

Change-Id: Iccacd06990d91e1cf3beb896d5b772d27e5e29ff

* fix(mail): reject --set-event-start/end/location without --set-event-summary

Change-Id: Icb651ff28ede526ff96b22e7b304b7bdea86d01f
Co-Authored-By: AI

* fix(mail): include --event-location in validateEventFlags; fix stale comment

Change-Id: I2f47016b6bfa11957dfe2c8c499cf36737efba53
Co-Authored-By: AI

* fix(mail): clear stale headers when wrapping single-leaf body in multipart/alternative

Change-Id: I29fe883c9151570f7939d372523b128cbea0b1ed
Co-Authored-By: AI

* fix(mail): add method=REQUEST to text/calendar MIME part created by set_calendar

Change-Id: I4d23674e20e4c42adab36385ff5ee8bb6d97625d
Co-Authored-By: AI

* fix(mail): use post-edit recipients for ICS attendees when --set-to combined with --set-event-*

Change-Id: I659e06635dd043f798d2f2e90d7dbca6e13d7f3d
Co-Authored-By: AI

* fix(mail): cover add_recipient/remove_recipient in ICS attendee resolution

Extract effectiveRecipients() to replay all three recipient op types
(set_recipients, add_recipient, remove_recipient) before building the
ICS for set_calendar, so patch-file recipient changes are reflected in
ATTENDEE metadata.

Change-Id: I3a7a55f96df8fac7d924a4dbeedd5b3d0d9d443c
Co-Authored-By: AI

* fix(mail): derive method= from ICS body in writeCalendarPart instead of hardcoding REQUEST

Passthrough ICS (e.g. forwarded METHOD:CANCEL) previously emitted a
Content-Type with method=REQUEST, disagreeing with the body. Now
extractICSMethod() scans the ICS for METHOD: and falls back to REQUEST
when absent, keeping existing behavior for our own generated ICS.

Change-Id: I4bf6c3755a189a436c2d26b082372d9f838f4051
Co-Authored-By: AI

* fix(mail): normalize calendar_event start/end to UTC in output

Callers expect RFC 3339 UTC strings; source ICS with TZID offsets
previously emitted +08:00 instead of Z.

Change-Id: I88bd4b925f8fc3b4f569e41712ae58ab50d94a2f
Co-Authored-By: AI

* fix(mail): make ICS parser case-insensitive and handle parameterized property names

RFC 5545 §3.1 allows any case and optional parameters on all property
names. Unify UID/SUMMARY/LOCATION/DTSTART/etc. to compare via
strings.ToUpper(name) and add HasPrefix checks for the NAME; form,
consistent with how ORGANIZER and ATTENDEE were already handled.

Change-Id: I7dc642dd210a3256f2189a901a2d9518ea284815
Co-Authored-By: AI
2026-04-29 15:31:38 +08:00
feng zhi hao
af2398d636 feat(mail): add email template management + --template-id on compose (#642)
- `mail +template-create` / `mail +template-update` — manage personal
    email templates (name, subject, body, recipients, attachments,
    inline images).
  - `--template-id` on `+send` / `+draft-create` / `+reply` /
    `+reply-all` / `+forward` — apply a saved template when composing.
    Recipients / subject / body / attachments merge into the draft;
    explicit user flags take precedence.
2026-04-28 21:14:01 +08:00
chanthuang
2e7a11a8e8 feat(mail): support sharing emails to IM chats (#637)
* feat(mail): add +share-to-chat shortcut to share emails as IM cards

Two-step API (create share token → send card) wrapped in a single
shortcut. Supports message-id/thread-id, five receive-id-type variants
(chat_id, open_id, user_id, union_id, email), and dry-run mode.

Change-Id: Ic7b8c01c0d25fef262f35be92555f1fd019bd679
Co-Authored-By: AI

* fix(mail): regenerate SKILL.md from skill-template instead of manual edit

Add missing safety rule 8 (draft link rule) to skill-template/domains/mail.md
so it survives regeneration. SKILL.md is now produced by `make gen-skills`
in the registry repo rather than hand-edited.

Change-Id: I9cf3605deae8b6de2042e40819fedc304967e78e
Co-Authored-By: AI

* fix(mail): add docstrings and use real validation path in tests

- Add Go doc comments to exported symbols for docstring coverage
- Rewrite tests to exercise MailShareToChat.Validate via RuntimeContext
  instead of duplicating validation logic
- Replace hand-rolled containsStr with strings.Contains
- Add httpmock stubs for execute and error path tests

Change-Id: Ic781494f61e9e844224185844bce7b0c48e8e200
Co-Authored-By: AI

* test(mail): add dry-run E2E test for +share-to-chat

Validate request shape (method, URL, mailbox path) under --dry-run
with fake credentials. Covers message-id, thread-id, and custom
mailbox variants.

Change-Id: Iae87bf141cbe4f312d3e9b1fca4ba175052c5c35
Co-Authored-By: AI

* fix(mail): include request body and params in dry-run output

DryRun now mirrors Execute: the share-token POST shows message_id or
thread_id, and the send POST shows receive_id_type and receive_id.
E2E test updated to assert these fields. Also fix strconv.Itoa usage.

Change-Id: I00f8770fd5a12b7354986c5e5077f97cfe5d6653

* style(mail): gofmt dry-run test file

Change-Id: I47dc6a9a47252dcfb7853737f88dfdaef65a0ae7

* test(mail): assert exact API call count in dry-run test

Change-Id: I9f4a1a183b55d03f5248eb4adddfddb08037ca95
2026-04-24 21:11:48 +08:00
xzcong0820
d92f0a2204 feat(mail): add read receipt support (--request-receipt, +send-receipt, +decline-receipt)
End-to-end RFC 3798 Message Disposition Notification support, covering
  both sides of the receipt flow — requesting a receipt when composing, and                                                                                                                                             
  responding to one (send or decline) when reading.                                                                                                                                                                     
  
  Request side (compose)                                                                                                                                                                                                
  - New --request-receipt flag on +send / +reply / +reply-all / +forward /
    +draft-create / +draft-edit. When set, the outgoing EML carries a                                                                                                                                                   
    Disposition-Notification-To header (RFC 3798) addressed to the resolved
    sender. Recipient mail clients may prompt the user, auto-send a receipt,                                                                                                                                            
    or silently ignore — delivery is not guaranteed.                                                                                                                                                                    
  - requireSenderForRequestReceipt gates the flag against a controlled
    sender address resolved BEFORE the orig.headTo fallback in +reply /                                                                                                                                                 
    +reply-all / +forward, so the DNT cannot silently land on someone else
    in CC / shared-mailbox flows.                                                                                                                                                                                       
                                                                                                                                                                                                                        
  Response side                                                                                                                                                                                                         
  - +send-receipt: build a system-templated reply for messages carrying the                                                                                                                                             
    READ_RECEIPT_REQUEST label (-607). Subject / recipient / sent / read
    time layout matches the Lark client; body is non-customizable — receipt                                                                                                                                             
    bodies are system templates by industry convention; free-form notes
    belong in +reply. Risk:"high-risk-write" + --yes required.                                                                                                                                                          
  - +decline-receipt: clear READ_RECEIPT_REQUEST without sending anything
    (mirrors the client's "不发送" / "Don't send" button). Idempotent on                                                                                                                                                
    re-run; Risk:"write" — no --yes needed.                       
                                                                                                                                                                                                                        
  Read-path hints                                                                                                                                                                                                       
  - +message / +messages / +thread emit a stderr hint when surfacing a                                                                                                                                                  
    mail carrying READ_RECEIPT_REQUEST, exposing BOTH response paths                                                                                                                                                    
    (+send-receipt --yes / +decline-receipt) so agents present a real                                                                                                                                                   
    choice to the user instead of silently auto-sending.
                                                                                                                                                                                                                        
  Guard rails                                                     
  - +send / +reply / +reply-all / +forward stay draft-by-default and
    require --confirm-send to send, gated by a dynamic scope check for                                                                                                                                                  
    mail:user_mailbox.message:send (absent from the default scope set so
    draft-only flows don't need the sensitive permission).                                                                                                                                                              
  - All header-bound user input (sender / display name / recipient /                                                                                                                                                    
    subject) goes through CR/LF rejection plus Bidi / zero-width / line-                                                                                                                                                
    separator guards, mirroring emlbuilder.validateHeaderValue, to block                                                                                                                                                
    header injection and visual spoofing.                                                                                                                                                                               
  - Hint output strips terminal control characters (CR, LF) from any
    untrusted field embedded into the user-visible suggestion.                                                                                                                                                          
                                                                                                                                                                                                                        
  Backend coupling                                                                                                                                                                                                      
  - Outgoing receipt EML carries the private header                                                                                                                                                                     
    X-Lark-Read-Receipt-Mail: 1. The data-access backend parses it into
    BodyExtra.IsReadReceiptMail; DraftSend then applies READ_RECEIPT_SENT                                                                                                                                               
    (-608) and clears READ_RECEIPT_REQUEST (-607) from the original                                                                                                                                                     
    message, closing the client-side banner.                                                                                                                                                                            
  - en receipts require backend TCC SubjectPrefixListForAdvancedSearch to                                                                                                                                               
    include "Read Receipt:" for conversation-view aggregation; zh prefix                                                                                                                                                
    ("已读回执:") is already configured.                                                                                                                                                                               
                                                                                                                                                                                                                        
  Docs: new reference pages for +send-receipt / +decline-receipt;                                                                                                                                                       
  --request-receipt noted on each compose-side reference; SKILL.md
  workflow (section 9) describes the full privacy-safe decision tree on                                                                                                                                                 
  both sides.                                                                                                                                                                                                           
                                                                                                                                                                                                                        
  Tests cover emlbuilder DispositionNotificationTo / IsReadReceiptMail                                                                                                                                                  
  helpers, receiptMetaLabels (zh / en), buildReceiptSubject, text and HTML
  body generators (with HTML escaping and Bidi guards), header-injection                                                                                                                                                
  defenses, sender-resolution gating (CC-only / shared-mailbox regression),
  hint emission paths, and the full +send-receipt / +decline-receipt happy                                                                                                                                              
  + idempotent paths via httpmock.
2026-04-24 14:26:17 +08:00
chanthuang
018eeb6414 fix(mail): remove leftover conflict marker in skill docs (#594)
The <<<<<<< HEAD marker was accidentally left in mail.md and SKILL.md
by commit cb301a3 (draft preview URL). Remove it.

Change-Id: I6e1d5c0c66761302a3c4ee1421a16961b666bd80
2026-04-21 21:58:01 +08:00
qioqio
cb301a3d1a feat(mail): add draft preview URL to draft operations (#438)
* feat(mail): add draft preview URL to draft operations

- Add draftPreviewURL helpers for send-preview link generation
- Integrate preview_url output in +draft-create, +draft-edit, +reply,
  +forward, +reply-all shortcuts
- Add unit tests (7 test cases, all passing)

Change-Id: Ie3cbb8f96b308aae225bc69f4c3fc2226af0c230

* fix(mail): derive draft preview url from meta service

Change-Id: Ibd10767bf4e4de7f453fff72487fe25090e14605

* fix: streamline mail draft and send outputs

Change-Id: I75a969af29fa862bdf94947a3aa775d6eebee812

* fix(mail): keep draft reference on create and update

Change-Id: Ie5787cf255ec2347c49f0a271209c1a2e4008fe3

* docs: refine mail draft link guidance for skills

Change-Id: Ieaa5afef310edd5253f07eef06678b7a5db38fc0

* fix(mail): return draft reference for save flows

Change-Id: Ied6031a05bdefecdcf60b09f66c5d3947d849f83

* refactor(mail): unify draft save output handling

Change-Id: I400b8f9df97d614b33da3cbdde410ef615444741

* fix(mail): surface automation disable reason

Change-Id: I23293fe6c2febf248c58ea14c87c05dde49872a1

* feat: flatten mail automation send disable output

Change-Id: I747bf54bc3251387b05d94f87fe61da958d78104

* fix(mail): address review feedback for draft docs and tests

Change-Id: I690df5612f36681c1690645d375c5c5e3ef9ca60

* test(mail): reuse upstream send-scope test factory

Change-Id: I7f73956696c5405d8eb81fcd2128f0e9898ea539

* refactor(mail): merge recall fields into send output helper

Change-Id: I5af612d70b05a3c0d8abbc9561fe76bb83b5b359

* fix(mail): omit raw recall status from send output

Change-Id: I2918226a0eb68a45f6cc4ea997e1c941d8c16d52

* style(mail): format send output tests

Change-Id: I8e0ec37aac48bcda6b5ad948f397d184a2a4d81d

* test(mail): cover draft reference output flows

Change-Id: Idd8abdb84613727a24e3fccb7b329e69566bc890
2026-04-21 20:55:41 +08:00
feng zhi hao
be79485fe3 feat: mail support scheduled send (#534)
feat: mail support scheduled send (#534)
2026-04-17 15:41:42 +08:00
chanthuang
03ba542a60 Revert "feat: mail support scheduled send (#449)" (#492)
This reverts commit 44e7b5b477.

Change-Id: I0b0c6454cf5ea4c15169a3c683b91795ef880478
2026-04-15 21:04:27 +08:00
feng zhi hao
44e7b5b477 feat: mail support scheduled send (#449)
feat: mail support scheduled send
2026-04-15 14:11:19 +08:00
chanthuang
66ec27f6e1 feat(mail): support recipient search (#437)
* feat(mail): add contact search workflow and multi_entity search API

- Add recipient search workflow to mail skill template (search by name,
  email keyword, or group name with rich result display)
- Regenerate SKILL.md with multi_entity.search command

Change-Id: Ie307af16a5ee38dac99c1d8d0df528730bf847d0
Co-Authored-By: AI

* fix: require user confirmation for all contact search results

multi_entity.search is a fuzzy keyword search — a single result does
not guarantee an exact match (e.g. searching "张三" may only return
"张三丰"). Always show candidates for user confirmation before using
the email address in compose parameters.

Change-Id: I447c54cd59b06a88c5d6806bfe76f0adfdceb1ce
Co-Authored-By: AI
2026-04-15 12:33:50 +08:00
chanthuang
162c25527b feat(mail): support recall sent email (#481)
- Add buildSendResult helper that includes recall_available/recall_tip
  when backend returns recall_status in send response
- Update +send, +reply, +reply-all, +forward to use buildSendResult
- Add "Recall Email" section to mail skill template with recall and
  get_recall_detail command examples
- Regenerate SKILL.md

Change-Id: I44317ead8f8a65db81e874cfc3529ffeb21e1384
Co-Authored-By: AI
2026-04-15 12:31:25 +08:00
feng zhi hao
284e5b6606 feat(mail): add send_as alias support, mailbox/sender discovery APIs, and mail rules API
New capabilities:

  1. Alias (send_as) sending for all compose shortcuts (+send, +reply, +reply-all,
     +forward, +draft-create, +draft-edit):
     - New --mailbox flag separates mailbox routing from sender identity, enabling
       alias sending where --mailbox specifies the owning mailbox and --from
       specifies the alias address in the From header.
     - Example: --mailbox me --from alias@example.com --to bob@example.com
     - --mailbox priority: --mailbox > --from > "me"
     - --from priority: --from > --mailbox > profile("me")

  2. Discovery APIs for available mailboxes and sender addresses:
     - accessible_mailboxes: lists all mailboxes the user can access (primary + shared)
     - send_as: lists available sender addresses for a mailbox (primary, aliases, mailing lists)

  3. Mail rules API:
     - user_mailbox.rules resource: create, delete, list, reorder, update

  4. Reply-all self-exclusion improvement:
     fetchSelfEmailSet now also excludes the --from alias address, preventing the
     sender from appearing in the recipient list when replying via an alias.

  No breaking changes — omitting --mailbox preserves existing behavior.
2026-04-09 14:52:20 +08:00
chanthuang
51a6adab2b docs(mail): add identity guidance to prefer user over bot (#157)
* docs(mail): add identity guidance to prefer user over bot for mail APIs

Add an identity selection section to the mail skill documentation,
guiding AI agents to default to --as user when operating on mailboxes.
Bot identity requires the app to have tenant-level mail scopes enabled
in the developer console, which most apps do not.

* docs(mail): clarify identity selection wording and bot scope limits

- Replace ambiguous "默认使用" with "策略上应优先显式使用" to
  distinguish policy recommendation from CLI default (auto)
- Note that bot identity only supports read operations; all write
  operations (send, reply, forward, draft edit) require user identity
- Rewrite decision rules by read/write classification
2026-04-03 10:58:20 +08:00
feng zhi hao
10caeb5788 docs(mail): clarify JSON output is directly usable without extra encoding (#228)
Users reported that AI agents sometimes wrote shell scripts to manually
extract and re-decode JSON string fields (e.g. unicode_escape), causing
Chinese character corruption. Add notes to mail skill docs clarifying
that JSON output can be read directly without additional encoding
conversion.
2026-04-02 20:04:21 +08:00
梁硕
83dfb068ad feat: open-source lark-cli — the official CLI for Lark/Feishu
Change-Id: I113d9cdb5403cec347efe4595415e34a18b7decf
2026-03-28 10:36:25 +08:00