Glasshouse
루팅된 LG webOS TV용 대시보드·프라이버시 제어·Home Assistant 연동
Markdown 파일로 이메일을 작성·임시저장·전송하고, 헤더 제거·HTML 변환·표 스타일 적용·서명 추가·스레드 관리까지 지원
Compose, draft, and send emails from markdown files via the Gmail API. Strips markdown headers, converts to HTML with inline table styles, appends a standard signature, and handles threading. Wraps gm
개발 도구R · HTMLGitHub @NewGraphEnvironment온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Mail Composer — email composition and delivery via Gmail API
저장소 README에서 가져옴
README 전체를 불러오는 중입니다.
README 전문 보기 ↗Mail Composer. Three lines to draft an email.
Compose, draft, and send emails from markdown files via the Gmail API. Wraps gmailr to eliminate the 80 lines of boilerplate that every email script repeats.
pak::pak("NewGraphEnvironment/mc")
Set your default sender address in ~/.Rprofile:
options(mc.from = "[email protected]")
Or via environment variable in ~/.Renviron:
[email protected]
Then authenticate once per machine:
mc_auth()
Write your email body in markdown. Everything above the --- separator is
a human-readable envelope (notes for the author) and is stripped by
mc_md_render() before conversion. Recipients, subject, and other
envelope fields are set as R parameters in mc_send().
# Email to Brandon - Cottonwood
**Subject:** Cottonwood plugs - 2026 planting
**To:** [email protected]
---
Hi Brandon,
Quick question about the cottonwood plugs.
Thanks,
Al
Draft it in three lines:
library(mc)
mc_draft("communications/draft.md",
to = "[email protected]",
subject = "Cottonwood plugs - 2026 planting")
That creates a Gmail draft with HTML formatting and the standard signature
appended. Authentication happens automatically via cached OAuth tokens
(run mc_auth() once per machine to set up).
When you're ready to send for real, name the act:
mc_send("communications/draft.md",
to = "[email protected]",
subject = "Cottonwood plugs")
mc_draft() can only draft and mc_send() can only send — there is no flag
that flips one into the other. The same split applies to the frontmatter-driven
pair, mc_md_draft() and mc_md_send().
Need an R-generated table in your email? Use mc_compose() to mix markdown
files, HTML, and kable/kableExtra objects:
df <- data.frame(Site = c("Nechako", "Mackenzie"), Plugs = c(4000, 3000))
body <- mc_compose(
"communications/intro.md",
knitr::kable(df, format = "html"),
"<p>Let me know if this looks right.</p>"
)
mc_send(html = body, to = "[email protected]", subject = "Planting plan")
Large tables? Wrap in mc_scroll() for horizontal/vertical scrolling:
mc_compose(
"<p>Full dataset:</p>",
mc_scroll(knitr::kable(big_df, format = "html"), direction = "both")
)
See vignette("tables-in-emails") for kableExtra styling and scrolling examples.
Full function documentation with examples: newgraphenvironment.github.io/mc
Reply into an existing conversation:
# Find the thread
mc_thread_find("from:brandon subject:cottonwood")
# Read the conversation to review context
mc_thread_read("19c05f0a98188c91")
# Include drafts in the thread (adds a status column: "sent" / "draft")
mc_thread_read("19c05f0a98188c91", drafts = TRUE)
# Send into it
mc_send("draft.md",
to = "[email protected]",
subject = "Re: Cottonwood plugs",
thread_id = "19c05f0a98188c91")
Note: gm_create_draft() does not support thread_id. Drafts are always
standalone, and mc_draft() warns if you pass one. Use mc_send() to deliver
straight into a thread, or send the draft manually from the Gmail UI (Gmail
will match by subject line if it starts with "Re:").
Send an email later with send_at — either minutes from now or a specific
time. Use scheduler = "auto" for durable OS-native scheduling (recommended):
# Send in 10 minutes via launchd (macOS) or atd (Linux)
mc_send("draft.md",
to = "[email protected]",
subject = "Cottonwood plugs",
send_at = 10,
scheduler = "auto")
# Send at a specific time
mc_send("draft.md",
to = "[email protected]",
subject = "Cottonwood plugs",
send_at = as.POSIXct("2026-02-24 09:11:00"),
scheduler = "auto")
The scheduler argument selects the backend:
"callr" (default for backward compatibility) — callr::r_bg background R
process. Survives some session lifecycles but can be cleaned up if its
parent context exits (one-shot Rscript -e, RStudio sessions that close,
CI). Emits a warning() on use steering you toward "auto"."auto" — resolves to launchd on macOS or at on Linux. The OS-native
daemon owns the job lifecycle independent of any R session — survives
shell exit, parent process death, and (on macOS) sleep/wake cycles."launchd" / "at" — force a specific backend.Heartbeat log entries land in ~/.mc/send_log.txt so missed fires are
auditable from the log alone:
SCHEDULED at submission with the target timeSTARTED at fire, just before the actual sendSENT / SKIPPED / FAILED at outcomeA SCHEDULED line with no follow-up STARTED means the bg process died
before firing — the failure mode that the OS-native backends solve.
On macOS, caffeinate keeps the machine awake until the email sends (callr
backend only — launchd handles wake/sleep itself). If the machine sleeps
through the send window with the callr backend, a 5-minute grace period
applies — past that, the send is skipped to prevent stale emails.
Outcomes also trigger a macOS desktop notification on success, skip, or failure.
Apply Gmail labels to threads via mc_send(labels = ...) or in YAML
frontmatter as labels:. Missing user labels are auto-created on first use
(via mc_label_ensure()):
mc_send("draft.md",
to = "[email protected]",
subject = "Cottonwood plugs",
labels = c("project-x", "urgent"))
---
to: [email protected]
subject: Cottonwood plugs
labels:
- project-x
- urgent
---
Pass labels_create = FALSE for strict typo-guard (errors on unknown labels).
After-the-fact labelling on existing threads via mc_thread_modify(thread_id, add = ...) —
also accepts Gmail system labels like INBOX, STARRED, TRASH for
archive / star / trash workflows.
to_self = TRUE redirects to your own address, strips CC/BCC, and ignores
thread_id:
mc_send("draft.md",
to = "[email protected]",
subject = "Cottonwood plugs",
to_self = TRUE)
It caps who receives the message — it does not stop the send. If you want
nothing delivered at all, use mc_draft().
MIT