import * as wmill from "windmill-client"
import { S3Object } from "windmill-client"
/**
* Send Email
* Send an email from the connected Gmail account, with optional cc/bcc, HTML body, file attachments (from Windmill object storage) and a `from` send-as alias (see List Send-As Aliases; an unverified alias falls back to the primary address). To reply in a thread, pass the original's `thread_id` and its `Message-ID` header as `in_reply_to`, and keep the same subject. Requires gmail.send (the default scope), gmail.compose or gmail.modify on the connection.
*/
export async function main(
auth: RT.Gmail,
to: string,
subject: string,
body: string,
cc: string | undefined,
bcc: string | undefined,
from: string | undefined,
is_html: boolean = false,
attachments: S3Object[] | undefined,
thread_id: string | undefined,
in_reply_to: string | undefined
) {
const boundary = `wm_${crypto.randomUUID()}`
const headers = [
from ? `From: ${from}` : undefined,
`To: ${to}`,
cc ? `Cc: ${cc}` : undefined,
bcc ? `Bcc: ${bcc}` : undefined,
`Subject: =?UTF-8?B?${b64(subject)}?=`,
in_reply_to ? `In-Reply-To: ${in_reply_to}` : undefined,
in_reply_to ? `References: ${in_reply_to}` : undefined,
"MIME-Version: 1.0",
].filter((h) => h !== undefined)
const text = [
`Content-Type: text/${is_html ? "html" : "plain"}; charset="UTF-8"`,
"Content-Transfer-Encoding: base64",
"",
wrap(b64(body)),
].join("\r\n")
let mime: string
if (!attachments?.length) {
mime = `${headers.join("\r\n")}\r\n${text}`
} else {
const parts = [text]
for (const file of attachments) {
const bytes = await wmill.loadS3File(file)
if (!bytes) throw new Error(`Attachment not found: ${file.s3}`)
const name = file.s3.split("/").pop()!
parts.push(
[
`Content-Type: ${Bun.file(name).type}; name="${name}"`,
`Content-Disposition: attachment; filename="${name}"`,
"Content-Transfer-Encoding: base64",
"",
wrap(b64(bytes)),
].join("\r\n")
)
}
mime = [
...headers,
`Content-Type: multipart/mixed; boundary="${boundary}"`,
"",
...parts.map((p) => `--${boundary}\r\n${p}`),
`--${boundary}--`,
].join("\r\n")
}
const response = await fetch(
"https://gmail.googleapis.com/gmail/v1/users/me/messages/send",
{
method: "POST",
headers: {
Authorization: `Bearer ${auth.token}`,
"Content-Type": "application/json",
Accept: "application/json",
},
body: JSON.stringify({
raw: Buffer.from(mime).toString("base64url"),
threadId: thread_id || undefined,
}),
}
)
if (!response.ok) {
throw new Error(`${response.status} ${await response.text()}`)
}
return await response.json()
}
function b64(s: string | Uint8Array) {
return Buffer.from(s).toString("base64")
}
function wrap(s: string) {
return s.replace(/.{76}/g, "$&\r\n")
}
Submitted by hugo989 6 hours ago