Skip to content

feat(mail): support scheduled send via --send-time#449

Merged
infeng merged 6 commits intomainfrom
feat/mail-scheduled-send
Apr 15, 2026
Merged

feat(mail): support scheduled send via --send-time#449
infeng merged 6 commits intomainfrom
feat/mail-scheduled-send

Conversation

@infeng
Copy link
Copy Markdown
Collaborator

@infeng infeng commented Apr 13, 2026

Summary

  • +send+reply+reply-all+forward 四个 shortcut 新增 --send-time 参数,支持定时发送邮件
  • 底层 draft.Send 函数增加 sendTime 参数,透传至 API 请求体
  • 文档补充了定时发送场景示例和取消定时发送说明

Test plan

  • +send --confirm-send --send-time <timestamp> 定时发送新邮件
  • +reply --confirm-send --send-time <timestamp> 定时发送回复
  • +reply-all --confirm-send --send-time <timestamp> 定时发送回复全部
  • +forward --confirm-send --send-time <timestamp> 定时发送转发
  • cancel_scheduled_send 取消定时发送后邮件恢复为草稿状态

Summary by CodeRabbit

  • New Features

    • Added scheduled email sending via --send-time (Unix timestamp; must be ≥ 5 minutes ahead)
    • --send-time supported for send, reply, reply-all, and forward when used with --confirm-send
    • Added cancel-scheduled-send flow that restores messages to drafts
  • Behavior Changes

    • Scheduled sends do not yield an immediate message_id; advise checking send_status later and offer cancellation guidance
  • Documentation

    • Updated guides, examples, and status/cancellation workflows for scheduling

@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 Apr 13, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 13, 2026

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

Adds scheduled-send support: CLI shortcuts accept a Unix --send-time (validated ≥5 minutes ahead), pass it to draft.Send, which conditionally includes send_time in the POST body; documentation updated with scheduling and cancel flows.

Changes

Cohort / File(s) Summary
Draft service
shortcuts/mail/draft/service.go
Send signature extended to accept sendTime string; request body is nil when empty or {"send_time": sendTime} when provided.
CLI shortcuts
shortcuts/mail/mail_send.go, shortcuts/mail/mail_forward.go, shortcuts/mail/mail_reply.go, shortcuts/mail/mail_reply_all.go
Added --send-time flag (Unix seconds); call validateSendTime(...) during validation; read sendTime := runtime.Str("send-time") and pass to draftpkg.Send(...).
Helpers
shortcuts/mail/helpers.go
Added validateSendTime(runtime *common.RuntimeContext) error: requires --confirm-send when --send-time set, parses timestamp, enforces minimum of now + 5 minutes.
Docs / Skill references
skill-template/domains/mail.md, skills/lark-mail/SKILL.md, skills/lark-mail/references/lark-mail-send.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
Documented --send-time usage and constraint, added scheduled-send and cancel scenarios, clarified send_status behavior for immediate vs scheduled sends, and documented cancel_scheduled_send and permission notes.

Sequence Diagram

sequenceDiagram
    actor User
    participant CLI as "CLI Command"
    participant Service as "draft.Send()"
    participant API as "Backend API"

    User->>CLI: Run command with --send-time
    CLI->>CLI: Parse & validate send_time
    CLI->>Service: Send(runtime, mailboxID, draftID, sendTime)
    Service->>Service: Build request body (include send_time if set)
    Service->>API: POST /drafts/{draftID}/send (body includes {"send_time": timestamp})
    API->>API: Schedule delivery or send immediately
    API-->>Service: Return result/status
    Service-->>CLI: Return response
    CLI-->>User: Confirm scheduled send
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • chanthuang

Poem

🐇 I nibble timestamps in the grass,
I tuck your drafts for later to pass,
With --send-time set and validated right,
They hop away at the scheduled light,
Thump—your message hops off at last ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main feature being added: support for scheduled email sending via a new --send-time parameter.
Description check ✅ Passed The description is well-structured, follows the required template, and includes all necessary sections: Summary (explaining the feature), Changes (listing modifications across shortcuts and documentation), and Test Plan (with specific test cases).

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/mail-scheduled-send

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.

@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Apr 13, 2026

Greptile Summary

This PR adds --send-time (Unix timestamp) to the +send, +reply, +reply-all, and +forward shortcuts, threading the value through draft.Send to the Lark API's scheduled-send endpoint, with matching documentation updates.

Two bugs need to be fixed before merging:

  • send_time type mismatch in service.go: the timestamp is inserted into the JSON body as a Go string, producing {\"send_time\": \"1744608000\"} instead of the integer form {\"send_time\": 1744608000} that the API expects. This will cause API rejection for every scheduled-send attempt via the shortcut.
  • Silent no-op when --send-time is used without --confirm-send: all four shortcuts read sendTime but discard it at the early-return guard; the user's scheduled-send intent is silently dropped with no error or warning.

Confidence Score: 4/5

Two P1 bugs prevent the scheduled-send feature from working correctly; existing (non-scheduled) send paths are unaffected.

The send_time string-vs-integer type mismatch will cause all --send-time invocations via the shortcut to fail at the API level, and the missing validation silently discards the flag when --confirm-send is absent — both are present defects on the new code path.

shortcuts/mail/draft/service.go (type fix) and all four shortcut files for the validation guard.

Important Files Changed

Filename Overview
shortcuts/mail/draft/service.go Adds sendTime param to Send; critical bug: value stored as string in JSON body but API expects integer, breaking scheduled sends
shortcuts/mail/mail_send.go Adds --send-time flag and threads it to draft.Send; missing validation that --send-time requires --confirm-send
shortcuts/mail/mail_reply.go Adds --send-time flag; same missing validation as mail_send.go — flag silently dropped without --confirm-send
shortcuts/mail/mail_reply_all.go Adds --send-time flag; same missing validation as mail_send.go — flag silently dropped without --confirm-send
shortcuts/mail/mail_forward.go Adds --send-time flag; same missing validation as mail_send.go — flag silently dropped without --confirm-send
skill-template/domains/mail.md Documentation updated with scheduled-send table, cancel_scheduled_send instructions, and --send-time usage notes — looks correct
skills/lark-mail/SKILL.md Skill documentation updated consistently with scheduled-send table, notes, and cancel_scheduled_send API listing
skills/lark-mail/references/lark-mail-send.md Reference updated with --send-time parameter docs and scenario examples for scheduled and cancelled sends
skills/lark-mail/references/lark-mail-reply.md Reference updated consistently with --send-time parameter docs and scheduled-send scenarios
skills/lark-mail/references/lark-mail-reply-all.md Reference updated consistently with --send-time parameter docs and scheduled-send scenarios
skills/lark-mail/references/lark-mail-forward.md Reference updated consistently with --send-time parameter docs and scheduled-send scenarios

Sequence Diagram

sequenceDiagram
    participant User
    participant Shortcut as +send / +reply / +reply-all / +forward
    participant DraftSvc as draft.Send()
    participant LarkAPI as Lark Mail API

    User->>Shortcut: --confirm-send --send-time <timestamp>
    Shortcut->>Shortcut: CreateWithRaw() → draft_id
    Shortcut->>DraftSvc: Send(mailboxID, draftID, sendTime string)
    Note over DraftSvc: ⚠ bodyParams["send_time"] = sendTime (string)<br/>API expects integer
    DraftSvc->>LarkAPI: POST .../drafts/{id}/send<br/>{"send_time": "1744608000"}
    LarkAPI-->>DraftSvc: Error / ignores field (type mismatch)
    DraftSvc-->>Shortcut: error or unscheduled send

    Note over User,Shortcut: If --send-time used WITHOUT --confirm-send:<br/>sendTime is read but silently discarded → plain draft saved
Loading

Comments Outside Diff (1)

  1. shortcuts/mail/mail_send.go, line 62-67 (link)

    P1 --send-time silently dropped when --confirm-send is absent

    When a user calls +send --send-time 1744608000 without --confirm-send, the sendTime value is read at line 78 but the Execute function returns early at the !confirmSend guard (line 142), so the timestamp is never used and the email is saved as a plain draft with no scheduled delivery. The user receives no error or warning, and will likely believe the send has been scheduled.

    A validation check should reject this combination early:

    Validate: func(ctx context.Context, runtime *common.RuntimeContext) error {
        if runtime.Str("send-time") != "" && !runtime.Bool("confirm-send") {
            return fmt.Errorf("--send-time requires --confirm-send; without it the email is only saved as a draft")
        }
        // existing checks …
    },

    The same issue exists in mail_reply.go, mail_reply_all.go, and mail_forward.go.

Reviews (1): Last reviewed commit: "feat: mail support scheduled send" | Re-trigger Greptile

@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 13, 2026

🚀 PR Preview Install Guide

🧰 CLI update

npm i -g https://pkg.pr.new/larksuite/cli/@larksuite/cli@4c2c0c8dfdda29a016e24b739bf9c6f4343f258d

🧩 Skill update

npx skills add larksuite/cli#feat/mail-scheduled-send -y -g

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 10

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@shortcuts/mail/mail_reply.go`:
- Line 35: Validate the "--send-time" flag locally before proceeding to send: in
the mail send/reply/forward handlers in shortcuts/mail/mail_reply.go (the code
paths around the existing send handling and the locations referenced by the
review: ~line 35, ~72, ~186), ensure you check that if a send-time value is
provided then "--confirm-send" is also set and the timestamp is at least 5
minutes in the future; if either check fails, return a clear user-facing error
instead of proceeding (apply the same validation pattern to the +send,
+reply-all and +forward handlers).

In `@skill-template/domains/mail.md`:
- Line 75: The example Unix timestamp `1744608000` in the note about scheduled
sends is stale and violates the "now + 5 minutes" requirement; update the
example to a future timestamp (e.g., pick a value at least 5 minutes ahead of
the current time) and ensure the text around `--send-time`, `--confirm-send`,
and `send_time` still clearly states the requirement that `--send-time` must be
used with `--confirm-send` and represent a Unix timestamp in seconds (now + 5
minutes minimum).

In `@skills/lark-mail/references/lark-mail-forward.md`:
- Line 70: The example Unix timestamp for `--send-time <timestamp>` is wrong and
in the past (uses 1744608000); update the example to the correct Unix timestamp
for "2026-04-14 15:00" (1776178800) or replace examples with a clear placeholder
like `<unix_timestamp>`; apply the same change to the other occurrences
referenced (the block around the current example and the instances noted at
lines 123-127) so the narrative time and example timestamps are consistent.

In `@skills/lark-mail/references/lark-mail-reply-all.md`:
- Around line 161-164: The paragraph about scheduled sending with `--send-time`
is self-contradictory: it first says there will be no `message_id` immediately
and then implies `send_status` can be queried immediately; change the text to
consistently instruct callers not to call `send_status` when `message_id` is
absent (i.e., for scheduled sends), and instead state they should either wait
until the scheduled send time or wait until a `message_id` is returned before
calling `send_status`; keep references to `--send-time`, `message_id`, and
`send_status` to make the behavior clear.
- Around line 127-131: The human-readable send time "2026-04-14 15:00" and the
example Unix timestamp (1744608000) are inconsistent; update the example in the
lark-cli mail user_mailbox.drafts send snippet so the send_time matches the
displayed time (e.g., replace the incorrect 1744608000 with the correct Unix
seconds for 2026-04-14 15:00 UTC: 1776178800) and add a brief note that
send_time should be in seconds and at least current_time + 5 minutes; target the
send_time field and the lark-cli mail user_mailbox.drafts send example to make
this change.

In `@skills/lark-mail/references/lark-mail-reply.md`:
- Line 77: Update the inconsistent example for the `--send-time <timestamp>`
option: either replace the hardcoded Unix timestamp `1744608000` with one that
matches the displayed datetime "2026-04-14 15:00" (or vice versa), or swap both
to a clear placeholder like `<unix_timestamp>`; apply the same fix to the other
occurrences referencing `--send-time <timestamp>` (the block around the
additional examples mentioned) so the human-readable datetime and Unix timestamp
are consistent throughout.

In `@skills/lark-mail/references/lark-mail-send.md`:
- Around line 129-133: The example uses a human-readable send time "2026-04-14
15:00" but supplies a mismatched Unix timestamp 1744608000 for send_time; update
the send_time value in the lark-cli example (the JSON --data
'{"send_time":...}') to the correct Unix timestamp that corresponds to
"2026-04-14 15:00" (or change the human-readable text to match the existing
timestamp), ensuring the --data send_time matches the displayed time and still
satisfies the "current time + 5 minutes" requirement; refer to the lark-cli mail
user_mailbox.drafts send command and the send_time field/draft_id placeholder
when making the correction.
- Around line 156-157: Clarify the documentation to remove the logical conflict
between "message_id is not generated immediately" and "`send_status` returns
'pending'": state explicitly that send_status can only be queried when a
message_id is available, and for scheduled sends the system may return a
'pending' send_status without a message_id until the scheduled job is
created/executed; update the paragraph to say: for scheduled sends, do not query
send_status immediately—wait until a message_id is returned (or until after the
scheduled send time), then use that message_id to query send_status.

In `@skills/lark-mail/SKILL.md`:
- Line 89: Update the example for `--send-time` in SKILL.md so the sample Unix
timestamp matches the 2026 example date used elsewhere (or replace the hardcoded
`1744608000` with a note to compute the Unix seconds dynamically), and ensure
the surrounding text referencing `--send-time`, `--confirm-send`, and
`send_time` still states that the timestamp is in seconds and must be at least
current time + 5 minutes.
- Around line 136-137: The scheduled-send paragraph mentioning "--send-time",
"message_id", and "send_status" is ambiguous; update the SKILL.md paragraph to
explicitly state that when a scheduled send does not immediately return a
message_id you must not query send_status (i.e., wait until you have a
message_id or until the scheduled send time has passed), and add a clear
sentence such as "If no message_id is returned for a scheduled send, do not
query send_status until a message_id is obtained or the scheduled time has
passed" to close the loop.
🪄 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: f900c828-6446-4983-b946-3307d21f0c2e

📥 Commits

Reviewing files that changed from the base of the PR and between 25534d7 and 13d67af.

📒 Files selected for processing (11)
  • shortcuts/mail/draft/service.go
  • shortcuts/mail/mail_forward.go
  • shortcuts/mail/mail_reply.go
  • shortcuts/mail/mail_reply_all.go
  • shortcuts/mail/mail_send.go
  • skill-template/domains/mail.md
  • skills/lark-mail/SKILL.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

- Pass nil body instead of empty map when sendTime is absent in draft.Send()
- Add validateSendTime() to check timestamp format and >=now+5min constraint
- Call validateSendTime in all 4 handler Validate funcs (send/reply/reply-all/forward)
- Replace hardcoded 1744608000 with <unix_timestamp> placeholder in all docs

Co-Authored-By: AI
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

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 the current code and only fix it if needed.

Inline comments:
In `@skills/lark-mail/references/lark-mail-send.md`:
- Line 129: The example confirmation string contains a stale hardcoded schedule
"2026-04-14 15:00" which conflicts with the "当前时间 + 5 分钟" rule; update the
example in the confirmation text (the line showing: 邮件草稿已创建:收件人
alice@example.com,主题「周报」,定时 2026-04-14 15:00 发送。确认吗?) to either use a relative
placeholder like "定时 当前时间 + 5 分钟 发送" or a template token (e.g.,
"{{now_plus_5min}}") so the example stays correct and consistent with the
scheduling rule.
🪄 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: 724e668c-6253-40ff-b0bf-90a8a216677b

📥 Commits

Reviewing files that changed from the base of the PR and between 13d67af and c3c3198.

📒 Files selected for processing (12)
  • shortcuts/mail/draft/service.go
  • shortcuts/mail/helpers.go
  • shortcuts/mail/mail_forward.go
  • shortcuts/mail/mail_reply.go
  • shortcuts/mail/mail_reply_all.go
  • shortcuts/mail/mail_send.go
  • skill-template/domains/mail.md
  • skills/lark-mail/SKILL.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
🚧 Files skipped from review as they are similar to previous changes (9)
  • shortcuts/mail/mail_reply.go
  • shortcuts/mail/mail_reply_all.go
  • shortcuts/mail/draft/service.go
  • skills/lark-mail/references/lark-mail-forward.md
  • skills/lark-mail/references/lark-mail-reply.md
  • shortcuts/mail/mail_send.go
  • skills/lark-mail/references/lark-mail-reply-all.md
  • shortcuts/mail/mail_forward.go
  • skills/lark-mail/SKILL.md

Replace "2026-04-14 15:00" with "<目标时间>" placeholder in all
scheduled-send scenario examples to avoid stale dates.

Co-Authored-By: AI
infeng added 2 commits April 15, 2026 11:47
…d for scheduled sends

- validateSendTime now rejects --send-time without --confirm-send
- Scheduled send output includes draft_id, scheduled_send_time, and
  cancel_tip so users can cancel via cancel_scheduled_send
- Applied to all 4 handlers (send/reply/reply-all/forward)
Scheduled sends do return message_id; cancellation also uses
message_id. The only limitation is send_status cannot be queried
immediately. The extra draft_id/cancel_tip output was unnecessary.
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

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 the current code and only fix it if needed.

Inline comments:
In `@shortcuts/mail/mail_reply_all.go`:
- Line 77: The code reads the raw --send-time into sendTime using
runtime.Str("send-time") without trimming, so untrimmed values can be validated
but later passed to draftpkg.Send()/output with surrounding whitespace; change
the source to trim whitespace once (e.g., replace the raw assignment of sendTime
in mail_reply_all.go with a trimmed value) and ensure the trimmed variable is
used everywhere thereafter (including where validateSendTime is called and where
draftpkg.Send() is invoked); apply the same single-source trim fix to the
analogous variables in mail_reply.go and mail_forward.go so all send-time values
are normalized before any validation or sending.
🪄 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: 06bd459b-9ede-45bb-907b-f7d3e828bede

📥 Commits

Reviewing files that changed from the base of the PR and between 6617580 and a828e60.

📒 Files selected for processing (5)
  • shortcuts/mail/helpers.go
  • shortcuts/mail/mail_forward.go
  • shortcuts/mail/mail_reply.go
  • shortcuts/mail/mail_reply_all.go
  • shortcuts/mail/mail_send.go
✅ Files skipped from review due to trivial changes (1)
  • shortcuts/mail/helpers.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • shortcuts/mail/mail_send.go

Copy link
Copy Markdown
Collaborator

@chanthuang chanthuang left a comment

Choose a reason for hiding this comment

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

LGTM. Conflict resolution is clean — recall feature (buildSendResult) preserved correctly across all 4 shortcuts. The --confirm-send dependency check in validateSendTime addresses the earlier must-fix.

@infeng infeng merged commit 44e7b5b into main Apr 15, 2026
15 checks passed
@infeng infeng deleted the feat/mail-scheduled-send branch April 15, 2026 06:11
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/M Single-domain feat or fix with limited business impact

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants