Leveraging ArrayBuffer to Convert Images to Base64 for Email Notifications

Blog

Posted by Nuno Marques on 14 Dec 2024

When building dynamic web applications like Bokkah, efficiently handling image data is crucial, especially when integrating features like sending email notifications for friend requests, invitation confirmations, or accepted requests. Inline Base64-encoded images in <img src=""> attributes can make these emails visually appealing without external hosting dependencies.

In this article, we’ll explore how ArrayBuffer can be utilized to correctly fetch an image and encode it to a valid Base64 string, addressing common pitfalls.


Why Use ArrayBuffer?

ArrayBuffer provides a mechanism to handle raw binary data. It enables fetching an image, decoding it into binary, and encoding it back into Base64—a format suitable for embedding directly in HTML or CSS.

The Problem with Base64 Conversion

An improperly implemented Base64 conversion can result in broken or unreadable images. Common mistakes include:

  • Skipping the Content-Type or using incorrect MIME types.
  • Encoding improperly parsed binary data.
  • Failing to handle fetch errors gracefully.

Correct Implementation

Here’s an improved utility function to fetch an image and convert it into a Base64-encoded string. This addresses issues like MIME type consistency and ensures valid encoding.

Working Code Snippet

import fetch from 'node-fetch';

// Function to fetch an image and convert it to Base64
export const fetchImageAsBase64 = async (imageUrl) => {
    try {
        const response = await fetch(imageUrl);
        if (!response.ok) {
            throw new Error(`Failed to fetch image: ${response.statusText}`);
        }

        // Read image as ArrayBuffer
        const arrayBuffer = await response.arrayBuffer();
        const base64Image = Buffer.from(arrayBuffer).toString('base64');
        
        // Get MIME type dynamically
        const mimeType = response.headers.get('content-type');
        if (!mimeType.startsWith('image')) {
            throw new Error(`The URL provided is not an image: ${mimeType}`);
        }

        // Return Base64-encoded string with MIME type
        return `data:${mimeType};base64,${base64Image}`;
    } catch (error) {
        console.error(`Error fetching or converting image: ${error.message}`);
        throw error;
    }
};

// Example usage
(async () => {
    try {
        const imageUrl = 'https://example.com/path-to-image.jpg';
        const base64String = await fetchImageAsBase64(imageUrl);
        console.log(base64String); // Embed in <img src=""/>
    } catch (error) {
        console.error(error.message);
    }
})();

Key Improvements in This Implementation

  1. Dynamic MIME Type Handling: The function detects the content type from HTTP headers, ensuring accurate encoding.
  2. Error Handling: Gracefully handles errors such as network issues or non-image URLs.
  3. Compatibility: Works with server-side environments like Node.js and ensures valid Base64 encoding using Buffer.

Practical Use Case

Imagine sending an email notification for a new friend request:

<!DOCTYPE html>
<html>
<body>
    <h1>You Have a New Friend Request!</h1>
    <img src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD..." alt="User Image">
</body>
</html>

Replace the src attribute dynamically with the Base64-encoded string generated by the utility function.

Conclusion

Using ArrayBuffer for binary data processing and encoding is a robust approach to embedding images in email templates. By following the improved function above, you can ensure seamless integration of inline images for email notifications, enhancing user experience.