1

Send Email via GMail with correct encoding of German umlauts in Subject

by
Published Feb 6, 2025

Variation of the standard "Send via GMail" script but with support for correct UTF-8 encoding of German umlauts and other special characters in the subject. i.e.: - Standard script: "Aufgeräumter Arbeitsplatz" - This script: "Aufgeräumter Arbeitsplatz"

Script gmail
  • Submitted by alexander koderman64 Bun
    Created 502 days ago
    1
    import { encode as base64UrlEncode } from "https://deno.land/[email protected]/encoding/base64url.ts";
    2
    
    
    3
    /**
    4
     * @param user_id User's email address. The special value `me` can be used to indicate the authenticated user.
    5
     */
    6
    type Gmail = {
    7
      token: string;
    8
    };
    9
    
    
    10
    // Helper function to Base64-encode UTF-8 strings
    11
    function base64EncodeUTF8(str) {
    12
      // Encode string as UTF-8 then convert to base64
    13
      return btoa(unescape(encodeURIComponent(str)));
    14
    }
    15
    
    
    16
    export async function main(
    17
      gmail_auth: Gmail,
    18
      to_email: string,
    19
      subject: string,
    20
      message: string,
    21
      user_id: string = "me",
    22
    ) {
    23
      const token = gmail_auth["token"];
    24
      if (!token) {
    25
        throw Error(`
    26
        No authentication token was found.
    27
        Go to "https://app.windmill.dev/resources?connect_app=gmail" to connect Gmail, 
    28
        then select your token from the dropdown in the arguments window.
    29
        (Click "Refresh" if you don't see your resource in the list.)\n`);
    30
      }
    31
    
    
    32
      // This breaks subject encoding of umlauts:
    33
      //const text =
    34
      //  `From: <${user_id}>\nTo: <${to_email}>\nSubject: ${subject}\nContent-Type: text/html; charset="UTF-8"\n\r <p>${message}</p>`;
    35
      //const textEncoder = new TextEncoder();
    36
      //const email = base64UrlEncode(textEncoder.encode(text));
    37
      //const body = JSON.stringify({
    38
      //  raw: email,
    39
      //});
    40
    
    
    41
      // Instead: wrap the encoded subject in RFC 2047 format
    42
      const encodedSubject = `=?UTF-8?B?${base64EncodeUTF8(subject)}?=`;
    43
    
    
    44
      // Build the raw email string with the encoded subject header
    45
      const text = `From: <${user_id}>\n` +
    46
        `To: <${to_email}>\n` +
    47
        `Subject: ${encodedSubject}\n` +
    48
        `Content-Type: text/html; charset="UTF-8"\n\n` +
    49
        `<p>${message}</p>`;
    50
    
    
    51
      // Convert the email string into a Uint8Array and then Base64url encode it
    52
      const textEncoder = new TextEncoder();
    53
      const emailBytes = textEncoder.encode(text);
    54
      const email = base64UrlEncode(emailBytes);
    55
      
    56
      // Prepare the request body for the Gmail API
    57
      const body = JSON.stringify({
    58
        raw: email,
    59
      });
    60
    
    
    61
      const SEND_URL =
    62
        `https://gmail.googleapis.com/gmail/v1/users/${user_id}/messages/send`;
    63
    
    
    64
      const response = await fetch(SEND_URL, {
    65
        method: "POST",
    66
        headers: { Authorization: "Bearer " + token },
    67
        body,
    68
      });
    69
    
    
    70
      const result = await handleSendEmailResult(await response.json(), to_email);
    71
      return result;
    72
    }
    73
    
    
    74
    async function handleSendEmailResult(result: object, to_email: string) {
    75
      if (Object.keys(result).includes("error")) {
    76
        return Promise.reject({ wm_to_email: to_email, ...result });
    77
      }
    78
    
    
    79
      return result;
    80
    }
    81