Skip to content

Built for people who want to own their automations. Join the waitlist for an invite.

Package listing

@kentcdodds/google

README.md

100 lines · 5.5 KB · Markdown

@kentcdodds/google

Intent

Account-aware Google product helpers for Kent's Kody workflows. Centralizes explicit account selection (personal, business, youtube-brand, youtube-plus), OAuth integration routing, shared API error handling, and dry-run guards for Gmail, Calendar, Drive, People, YouTube, and YouTube Analytics. Use cal-com for Cal.com booking pages and lifecycle—not this package.

When To Use

  • Read or mutate Gmail, Google Calendar events, Drive files, or People contacts with the correct Google account.
  • Reply to a Gmail message with createReplyDraft, which quotes the original and sets threading headers from the message itself rather than from hand-copied values.
  • Call YouTube Data or YouTube Analytics APIs on Kent's main (youtube-brand) or plus (youtube-plus) channel.
  • Upload or update YouTube videos (including BEPE promo Shorts) via uploadVideo / updateVideo, fetching media from a URL such as Cloudflare R2.
  • Verify OAuth connectivity before a workflow touches Google APIs (smokeTest).
  • Resolve which Google account alias to pass when a task mentions personal Gmail, Workspace calendar, or a specific YouTube channel.

Required setup

Connect OAuth integrations at /connect/oauth (tokens are managed by Kody—not raw access-token secrets):

Account aliasOAuth integrationTypical use
personalgooglePersonal Gmail, Drive, default YouTube reads
businessgoogle-businessWorkspace Calendar and Gmail (me@kentcdodds.com)
youtube-brandgoogle-youtube-brandMain Kent C. Dodds YouTube channel
youtube-plusgoogle-youtube-pluskentcdodds-plus / BEPE channel

Every API call requires an explicit account param. Use dryRun: true before Gmail sends or Calendar mutations.

Exports

  • kody:@kentcdodds/google — package overview and smokeTest({ account }).
  • kody:@kentcdodds/google/accounts — list and resolve account aliases.
  • kody:@kentcdodds/google/core — low-level requestGoogle and getUserInfo.
  • kody:@kentcdodds/google/gmail — Gmail search, read, attachments, draft, threaded createReplyDraft with cc/bcc, composed createDraft/sendMessage, label modifyMessage/ensureLabel, send, URL parsing.
  • kody:@kentcdodds/google/calendar — Google Calendar CRUD, ACL, free/busy.
  • kody:@kentcdodds/google/drive — Drive search, metadata, export.
  • kody:@kentcdodds/google/people — People profile, contacts, connections.
  • kody:@kentcdodds/google/youtube — YouTube channels, search, videos, comments, resumable uploadVideo, and updateVideo.
  • kody:@kentcdodds/google/youtube-upload-video — resumable uploadVideo (package-invocation friendly default export).
  • kody:@kentcdodds/google/youtube-update-videoupdateVideo (package-invocation friendly default export).
  • kody:@kentcdodds/google/youtube-analytics — YouTube Analytics reports.
  • kody:@kentcdodds/google/youtube-channels — Kent channel registry (main / plus).
  • kody:@kentcdodds/google/types — shared param/result type metadata.

Example

import { listEvents } from 'kody:@kentcdodds/google/calendar'

export default async function main() {
	return await listEvents({ account: 'business', maxResults: 5 })
}

Replying to Gmail

createDraft takes a complete raw MIME string and stores it verbatim, so a caller that assembles its own message produces a reply with no quoted original. Quoting is a mail-client convention, not something the Gmail API adds.

createReplyDraft closes that gap. Pass the message id being replied to plus the reply text, and it derives the recipient, subject, In-Reply-To, References, threadId, and the quoted original from the fetched message. Only body comes from the caller, so quoted text and threading headers are copied by code instead of retyped.

import { createReplyDraft } from 'kody:@kentcdodds/google/gmail'

export default async function main() {
	return await createReplyDraft({
		account: 'business',
		replyToMessageId: '19fdd464c417fd87',
		body: ['Hi Adam,', 'Thanks for offering to record it.', '- Kent'],
		cc: 'sponsor-kcd@10xn.dev',
	})
}

Replies go out as multipart/related wrapping multipart/alternative, the same shape mail clients produce. The text/html part nests the original markup in a gmail_quote blockquote so quoted formatting, links, and screenshots survive, and inline images the quote references by cid: are re-attached so they still render. The text/plain part carries the usual > quoting, with existing markers deepened so nested history survives.

The attribution stamp uses the mailbox's own time zone, read from Calendar settings, because that is what clients display. Pass timeZone to override it.

Pass cc and bcc as a string or string list when the reply should copy someone. Those headers are not inferred from the original message. createDraft and sendMessage accept the same to / cc / bcc / subject / body fields when you are not assembling raw MIME yourself.

Pass dryRun: true to get back the assembled mime, text, html, resolved timeZone, and the inlineImages list without creating anything. Non-ASCII display names are RFC 2047 encoded. Re-attached inline images are capped by maxInlineImageBytes, and anything skipped is reported as skippedInlineImages.

Kent publishes to two YouTube channels: main (youtube-brand, Better with Kent) and plus (youtube-plus, BEPE / legacy Chats with Kent). Import resolveYouTubeChannel before upload or analytics work.