Home Portfolio Electronics Projects Embedded Systems CS Projects IoT & Security Blog About Contact

/ Umayanga's Blog

Documenting electronics projects, embedded systems development, IoT security experiments, and computer science research.

How to Use a Custom Domain Email with Gmail Using Cloudflare Email Routing
Blog Computer-Science Electronics Portfolio

How to Use a Custom Domain Email with Gmail Using Cloudflare Email Routing


Free Custom Domain Email — Cloudflare + Gmail Guide
☁ Cloudflare
✉ Gmail SMTP
Free Setup

Free Custom Domain Email
with Cloudflare + Gmail

Use contact@yourdomain.com with your existing Gmail inbox — no Google Workspace subscription needed.

INCOMING

Sender
MX Records
Cloudflare Routing
Gmail Inbox

OUTGOING

Gmail Compose
Gmail SMTP
Recipient

Before You Start

🌐A registered domain name
DNS managed via Cloudflare
An existing Gmail account

Configure Email Routing in Cloudflare

STEP 01 Enable Cloudflare Email Routing

Open the Cloudflare dashboard and select your domain. Navigate to Email → Email Routing and click Enable Email Routing.

dash.cloudflare.com

developers.cloudflare.com/email-routing Cloudflare Email Routing MX Records

Cloudflare automatically creates the required MX records:

MX 10route1.mx.cloudflare.net
MX 20route2.mx.cloudflare.net
Add Destination Address

Add your Gmail address as the forwarding destination. Cloudflare sends a verification email — open Gmail and confirm it.

Destination:yourgmail@gmail.com
Create a Routing Rule

Set up a routing rule to forward your custom address to Gmail.

Custom Address:contact@yourdomain.com
Destination:yourgmail@gmail.com

Any email sent to contact@yourdomain.com will now arrive in your Gmail inbox.

Create a Google Account with Your Custom Email

STEP 02 Google Account Signup

Go to the Google account creation page and choose "Use my current email address instead". Enter your custom domain email.

accounts.google.com/signup Google Signup Custom email signup
Email:contact@yourdomain.com

Google sends a verification code which arrives in your Gmail via Cloudflare forwarding.

Add Profile Picture

Go to myaccount.google.comPersonal Info → Profile Picture and upload your image. This appears on emails you send.

Generate a Gmail App Password

STEP 03 Create App Password for SMTP

Gmail SMTP requires an App Password (not your regular password).

myaccount.google.com/apppasswords
1.Security → Enable 2-Step Verification
2.Security → App Passwords
3.App: Mail · Device: Other (Custom)
4.Click Generate

Google generates a 16-character password:

abcd efgh ijkl mnop
⚠ Save this password immediately — it will not be shown again.

Add Custom Email in Gmail Send-As

STEP 04 Gmail Settings → Accounts and Import

In Gmail go to Settings → See all settings → Accounts and Import → Send mail as → Add another email address.

mail.google.com Gmail Settings Add email address SMTP Configuration
SMTP Server Settings
FieldValue
SMTP Serversmtp.gmail.com
Port587
Usernameyourgmail@gmail.com
Password[App Password from Step 3]
⚠ Username = your Gmail address, not your custom domain address.
Verify Email Address

Gmail sends a verification email to your custom address. It arrives in Gmail via Cloudflare forwarding. Enter the code or click the confirmation link.

Test Sending Email

STEP 05 Send a Test Email from Your Custom Domain

In Gmail, click Compose and use the From dropdown to select your custom domain address.

From:contact@yourdomain.com
To:another@email.com
Subject:Test custom domain email
Body:Testing Cloudflare email routing setup.

If configured correctly, the recipient sees contact@yourdomain.com as the sender.

Setup Summary

Domain DNS
Cloudflare
Incoming Mail
CF Email Routing
Mailbox
Gmail
Outgoing Mail
Gmail SMTP

Why This Setup?

Completely free custom domain email
No Google Workspace subscription
Familiar Gmail interface
Easy DNS management via Cloudflare

Official Documentation

Problem:  Commercial power monitors are too expensive and lack modular network integration.
Approach:  Engineered a custom IoT module featuring a highly precise sampling IC and seamless WiFi connectivity.
Future:  Integrating AI-based energy usage profiling.
Cloudflare Email Routing  +  Gmail SMTP  ·  Free Custom Domain Email Setup
How to Send Emails Using the Gmail API in Google Colab (With Every Error Fixed)
Blog Computer-Science

How to Send Emails Using the Gmail API in Google Colab (With Every Error Fixed)


How to Send Emails Using the Gmail API in Google Colab (With Every Error Fixed)

A practical, battle-tested guide — including all the errors you'll hit and exactly how to fix them.

Introduction

Sending emails programmatically using Python is incredibly useful — for automation, notifications, project alerts, or hobby projects like IoT devices. Google's Gmail API is one of the most reliable ways to do it, but getting it working inside Google Colab is surprisingly tricky. The official documentation assumes you're running on a local machine with a browser, which Colab doesn't have.

This guide walks you through the entire setup from scratch — Google Cloud Console, OAuth credentials, Python code — and documents every real error you'll encounter along the way, with the exact fix for each one.


What You'll Need

  • A Google account (Gmail)
  • A Google Cloud account (free) at console.cloud.google.com
  • A Google Colab notebook
  • (Optional) A custom domain email added as a Gmail alias

Step 1: Set Up Google Cloud Project

  1. Go to console.cloud.google.com
  2. Click "Select a project""New Project"
  3. Give it a name (e.g., mailsend-testtool) and click Create
Create Google Cloud Project

Step 2: Enable the Gmail API

  1. In your project, go to APIs & Services → Library
  2. Search for "Gmail API"
  3. Click it → Enable

Step 3: Configure the OAuth Consent Screen

  1. Go to APIs & Services → OAuth consent screen
  2. Choose External
  3. Fill in the required fields: App name, support email
  4. Under Scopes, add:
    https://www.googleapis.com/auth/gmail.send
  5. Under Test users, add your Gmail address
  6. Save and continue
Important: Because you added a sensitive scope (gmail.send), Google will mark your app as "unverified." This is completely normal for personal projects — you don't need to submit for verification. More on this below.

Step 4: Create OAuth 2.0 Credentials

  1. Go to APIs & Services → Credentials
  2. Click "+ Create Credentials"OAuth 2.0 Client ID
  3. Application type: Desktop app
  4. Click Create, then Download JSON
  5. This is your credentials.json file — keep it safe.

Also add http://localhost to Authorized redirect URIs in this credential (you'll need this later).


Step 5: Install Required Libraries in Colab

!pip install -q google-auth google-auth-oauthlib google-auth-httplib2 google-api-python-client

Step 6: The Working Code

Here is the complete, single-cell solution that works in Colab — with credentials embedded directly (no file upload needed) and the token saved to /tmp/ so it reuses automatically within the same session.

!pip install -q google-auth google-auth-oauthlib google-auth-httplib2 google-api-python-client

import base64, os, json
from email.message import EmailMessage
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from googleapiclient.discovery import build
from urllib.parse import urlparse, parse_qs

# ============================================================
# 🔧 PASTE YOUR credentials.json CONTENT HERE
# ============================================================
CREDENTIALS_JSON = {
  "installed": {
    "client_id": "YOUR_CLIENT_ID.apps.googleusercontent.com",
    "project_id": "your-project-id",
    "auth_uri": "https://accounts.google.com/o/oauth2/auth",
    "token_uri": "https://oauth2.googleapis.com/token",
    "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
    "client_secret": "YOUR_CLIENT_SECRET",
    "redirect_uris": ["http://localhost"]
  }
}

# ============================================================
# 📧 YOUR EMAIL ADDRESSES
# ============================================================
GMAIL      = 'you@gmail.com'
DOMAIN_ONE = 'you@yourdomain1.com'   # Custom domain alias 1
DOMAIN_TWO = 'you@yourdomain2.com'   # Custom domain alias 2

# ============================================================
# ⚙️  INTERNAL SETUP
# ============================================================
SCOPES     = ['https://www.googleapis.com/auth/gmail.send']
CREDS_FILE = '/tmp/credentials.json'
TOKEN_FILE = '/tmp/token.json'

# Write credentials dict to temp file
with open(CREDS_FILE, 'w') as f:
    json.dump(CREDENTIALS_JSON, f)


def get_credentials():
    creds = None

    # Load saved token if it exists
    if os.path.exists(TOKEN_FILE):
        creds = Credentials.from_authorized_user_file(TOKEN_FILE, SCOPES)

    # Auto-refresh if expired — no browser needed
    if creds and creds.expired and creds.refresh_token:
        creds.refresh(Request())
        with open(TOKEN_FILE, 'w') as f:
            f.write(creds.to_json())
        print("🔄 Token refreshed automatically.")
        return creds

    # First time only — manual auth
    if not creds or not creds.valid:
        flow = InstalledAppFlow.from_client_secrets_file(
            CREDS_FILE, SCOPES,
            redirect_uri='http://localhost'
        )
        auth_url, _ = flow.authorization_url(prompt='consent')
        print("=" * 60)
        print("👉 STEP 1: Open this URL in your browser:\n")
        print(auth_url)
        print("\n" + "=" * 60)
        print("👉 STEP 2: After approving, paste the full localhost URL")
        print("   below (even if the page didn't load — that's expected)\n")

        redirected_url = input("Paste URL here: ")
        code = parse_qs(urlparse(redirected_url).query)['code'][0]
        flow.fetch_token(code=code)
        creds = flow.credentials

        # Save token for reuse within this session
        with open(TOKEN_FILE, 'w') as f:
            f.write(creds.to_json())
        print("\n✅ Token saved! Next run will skip this step.")

    return creds


def send_email(to, subject, body, sender='me'):
    creds = get_credentials()
    service = build('gmail', 'v1', credentials=creds)

    msg = EmailMessage()
    msg['To'] = to
    msg['From'] = sender
    msg['Subject'] = subject
    msg.set_content(body)

    encoded = base64.urlsafe_b64encode(msg.as_bytes()).decode()
    result = service.users().messages().send(
        userId='me',
        body={'raw': encoded}
    ).execute()
    print(f"✅ Sent from [{sender}] → [{to}]")
    print(f"   Message ID: {result['id']}")


# ============================================================
# ✉️  SEND YOUR EMAIL
# ============================================================
send_email(
    to      = 'recipient@example.com',
    subject = 'Hello from Gmail API!',
    body    = 'This was sent via Gmail API from Google Colab.',
    sender  = DOMAIN_ONE    # swap to DOMAIN_TWO or GMAIL as needed
)

Sending from a Custom Domain Email

If you have a custom domain email (like you@yourdomain.com) added to Gmail as an alias, you can send from it directly. Just make sure it's set up in Gmail first:

Gmail → Settings → See all settings → Accounts and Import → Send mail as

Your custom domain email should be listed and verified there. Once it is, just pass it as the sender argument — no extra scopes or configuration needed.

# Send from your main Gmail
send_email(to='friend@example.com', subject='Hi', body='Hello!', sender=GMAIL)

# Send from custom domain 1
send_email(to='friend@example.com', subject='Hi', body='Hello!', sender=DOMAIN_ONE)

# Send from custom domain 2
send_email(to='friend@example.com', subject='Hi', body='Hello!', sender=DOMAIN_TWO)

Errors You'll Hit (And How to Fix Them)

This is the most important section. Here are every real error encountered during setup, in the order you'll face them.

❌ Error 1: could not locate runnable browser

Full error:

Error: could not locate runnable browser

Why it happens: The standard flow.run_local_server(port=0) tries to open a browser window on your machine. Colab runs on a remote server — there is no browser to open.

Fix: Don't use run_local_server() in Colab. Instead, manually generate the auth URL and handle the redirect yourself:

# ❌ This fails in Colab
creds = flow.run_local_server(port=0)

# ✅ This works in Colab
flow = InstalledAppFlow.from_client_secrets_file(
    'credentials.json', SCOPES,
    redirect_uri='http://localhost'
)
auth_url, _ = flow.authorization_url(prompt='consent')
print(auth_url)  # Open this in your browser manually

❌ Error 2: AttributeError: 'InstalledAppFlow' object has no attribute 'run_console'

Full error:

AttributeError: 'InstalledAppFlow' object has no attribute 'run_console'

Why it happens: Many older blog posts and Stack Overflow answers suggest using flow.run_console() as the Colab-friendly alternative to run_local_server(). However, run_console() was removed in newer versions of google-auth-oauthlib. Colab uses a recent version, so the method simply doesn't exist anymore.

Fix: Use the manual URL + redirect approach shown in the working code above. Generate the auth URL, open it in your browser, then capture the authorization code from the redirect URL.

❌ Error 3: Error 400: invalid_request — Access blocked

Full error (shown in browser):

Error 400: invalid_request
Access blocked: [your-app]'s request is invalid

Why it happens: Google deprecated the urn:ietf:wg:oauth:2.0:oob redirect URI in 2022. Many guides still recommend it, but Google now blocks it entirely.

Fix — Two parts:

Part A: Change your redirect URI in the code from oob to http://localhost:

# ❌ Deprecated — Google will block this
redirect_uri='urn:ietf:wg:oauth:2.0:oob'

# ✅ Use this instead
redirect_uri='http://localhost'

Part B: Add http://localhost to your OAuth client's authorized redirect URIs in Google Cloud Console:

  1. Go to APIs & Services → Credentials
  2. Click your OAuth 2.0 Client ID
  3. Under Authorized redirect URIs, click Add URI
  4. Add http://localhost
  5. Click Save

❌ Error 4: "This app isn't verified" warning in browser

What you see:

Google hasn't verified this app. The app is requesting access to sensitive info in your Google Account.

Why it happens: Your app uses a sensitive Gmail scope (gmail.send). Google requires verification for apps that will be used by the general public. Since this is a personal project, you don't need to submit for verification.

Fix:

  1. On the warning screen, click "Advanced"
  2. Click "Go to [your app name] (unsafe)"
  3. Grant permission

This is completely safe for your own personal project. Also make sure your Gmail address is added under Test users on the OAuth consent screen.


⚠️ Note: Token is Lost on Runtime Reset

The token is saved to /tmp/token.json. This folder is wiped whenever your Colab runtime resets (which happens after inactivity or manually). When that occurs, you'll need to go through the browser auth flow one more time.

Fix for persistent token across resets: Mount Google Drive and save the token there instead:

from google.colab import drive
drive.mount('/content/drive')

TOKEN_FILE = '/content/drive/MyDrive/gmail_token.json'

This way the token survives runtime resets and you only ever need to authenticate once.


How the Auth Flow Works (Summary)

Run What happens
First run Auth URL is printed → open in browser → approve → paste the localhost URL → token saved
Same session, next run Token loaded from /tmp/token.json — runs instantly
Token expired Auto-refreshed silently using the refresh token
Runtime reset /tmp/ is cleared → need to auth once more (use Drive to avoid this)

Conclusion

Getting the Gmail API working in Google Colab is more involved than the official docs suggest, mainly because Colab's headless server environment breaks the standard OAuth flow. The key lessons:

  • Don't use run_local_server() or run_console() in Colab
  • The oob redirect URI is deprecated — use http://localhost instead
  • The "unverified app" warning is normal — just click through it for personal use
  • Save your token to Google Drive if you want it to survive runtime resets
  • Sending from a custom domain alias just requires changing the sender field — no extra setup needed

Once it's working, you can reuse the send_email() function anywhere in your Colab notebook for notifications, alerts, or anything else your project needs.

E-Waste Digital Calculator Using 7-Segment Displays
Blog Electronics Portfolio

E-Waste Digital Calculator Using 7-Segment Displays


Binary Adder Calculator – First Year Electronics Project
First Year · Second Semester · Electronics Lab

Binary Adder
Calculator

PROJECT TYPE: Digital Logic Circuit  ·  COMPONENTS: E-Waste Recycled  ·  MAX OUTPUT: 198

Introduction

A digital calculator built from recycled electronic components (E-waste). The system adds two numbers and displays the result on three 7-segment displays.

Using binary counters, digital adder ICs, and display drivers, this project demonstrates practical digital arithmetic while promoting sustainable electronics engineering.

Completed during the First Year – Second Semester Electronics Laboratory.

Project Photo

Project Overview

The calculator generates two numbers via binary counters, adds them through binary adder ICs, converts the result to decimal digits, and drives 7-segment displays for output.

Binary AdditionHardware-level digital arithmetic
🖥
3× 7-Segment DisplaysDecimal result output
♻️
E-Waste ComponentsSalvaged from old boards
🔢
Max Value: 198Full 8-bit result range
🔁
4029 CountersGenerates input numbers 0–99
🧩
Custom PCBStable, compact design

System Block Diagram

System Block Diagram
System Diagram

Hardware Components

Component Function
4029 Counter ICGenerates input numbers (0 to 99)
74283 Binary Adder ICPerforms 4-bit binary addition
7511 Display DriverDrives 7-segment display segments
7-Segment DisplaysDisplays final decimal output
AND / OR Logic GatesBinary to decimal conversion logic
Recycled ComponentsICs, resistors, caps from E-waste boards

Circuit Design

STAGE 01 Number Generation — Counters

Two 4029 counter ICs generate the input numbers, each capable of counting from 0 to 99. Their binary outputs feed directly into the addition circuit as the two operands.

STAGE 02 Binary Addition — 74283 Adders

Two 74283 4-bit binary adder ICs are cascaded to produce an 8-bit result, covering the full sum range of the two counter inputs.

Binary Addition Circuit
STAGE 03 Binary to Decimal Conversion

The 8-bit binary sum is converted to three decimal digits using AND gates, OR gates, and additional adder circuits — producing BCD values suitable for driving the 7511 display driver ICs.

Binary to Decimal Conversion Circuit

PCB Design

To improve stability and compactness, the full circuit was transferred onto a custom-designed PCB.

Custom PCB Board

E-Waste Component Collection

ICs, resistors, capacitors, and displays were salvaged from discarded electronics, reducing e-waste and demonstrating sustainable engineering practice.

Project Demonstration

0:00
Video ended
Video demonstration — Binary addition on 7-segment displays

Final Output

The completed circuit performs binary addition of two numbers and shows the decimal result across three 7-segment displays.

000 → 198
display range (decimal)
Final build
Final build 2
Display close-up
PCB assembly
Wiring
Testing
Circuit detail
Completed board
Night build session

What I Learned

Binary addition using hardware circuits
Working principles of digital counters
Interfacing 7-segment displays
Digital logic with TTL ICs
PCB assembly and troubleshooting
Reusing electronic waste components