import { google } from 'googleapis'; import { env } from '$env/dynamic/private'; import quotedPrintable from 'quoted-printable'; // tiny, zero-dep package export const scopes = ['https://www.googleapis.com/auth/gmail.send']; export function getOAuthClient() { return new google.auth.OAuth2( env.GOOGLE_CLIENT_ID, env.GOOGLE_CLIENT_SECRET, env.GOOGLE_REDIRECT_URI ); } export function createAuthUrl() { return getOAuthClient().generateAuthUrl({ access_type: 'offline', prompt: 'consent', scope: scopes }); } export async function exchangeCodeForTokens(code: string) { const { tokens } = await getOAuthClient().getToken(code); if (!tokens.refresh_token) throw new Error('No refresh_token returned'); return tokens.refresh_token; } export async function sendGmail( refreshToken: string, { to, subject, text, qr_code }: { to: string; subject: string; text: string; qr_code: string } ) { const oauth = getOAuthClient(); oauth.setCredentials({ refresh_token: refreshToken }); const gmail = google.gmail({ version: 'v1', auth: oauth }); const message_html = `

${text}

QR Code

This email has been generated with the help of *insert software name*

`; const boundary = 'BOUNDARY'; const nl = '\r\n'; // RFC-5322 line ending const htmlQP = quotedPrintable.encode(message_html); const qrLines = qr_code.replace(/.{1,76}/g, '$&' + nl); const rawParts = [ 'MIME-Version: 1.0', `To: ${to}`, `Subject: ${subject}`, `Content-Type: multipart/related; boundary="${boundary}"`, '', `--${boundary}`, 'Content-Type: text/html; charset="UTF-8"', 'Content-Transfer-Encoding: quoted-printable', '', htmlQP, '', `--${boundary}`, 'Content-Type: image/png', 'Content-Transfer-Encoding: base64', 'Content-ID: ', 'Content-Disposition: inline; filename="qr.png"', '', qrLines, '', `--${boundary}--`, '' ]; const rawMessage = rawParts.join(nl); const raw = Buffer.from(rawMessage).toString('base64url'); await gmail.users.messages.send({ userId: 'me', requestBody: { raw } }); }