Open In App

Google Authentication and Fetching Mails from Scratch - Python Django

Last Updated : 17 May, 2025
Suggest changes
Share
Like Article
Like
Report

Google OAuth2 is a secure authorization protocol that allows applications to access user data without exposing their login credentials. Instead of asking for a username and password, OAuth2 lets users log in via Google and gives your app permission to access specific services (like Gmail) on their behalf.

In this tutorial, we’ll build a Django app from scratch that uses Google OAuth2 to authenticate users and access their Gmail inbox. We’ll use official Google libraries to handle the OAuth flow and interact with the Gmail API.

Step 1: Create and Configure a Django Project

First, create a new Django project and app:

django-admin startproject gfg_auth_project
cd gfg_auth_project
python manage.py startapp gfg_auth_app

Then, add the new app to INSTALLED_APPS in gfg_auth_project/settings.py:

INSTALLED_APPS = [
...
'gfg_auth_app',

]

Now install the required packages:

pip install django google-auth google-auth-oauthlib google-api-python-client

Then make the initial migrations and apply them:

python manage.py migrate

Step 2: Get Google OAuth Credentials

OAuth credentials allow your Django app to securely communicate with Google's servers. These credentials contain your app's identity and permissions. You'll need a credentials.json file that includes your client ID, client secret, and redirect URIs, this file is used in the OAuth 2.0 flow.

Follow these steps to get the credentials file:

  1. Go to Google Cloud Console
  2. Create a new project (or select an existing one)
  3. Enable the Gmail API
  4. Navigate to APIs & Services- Credentials
  5. Click Create Credentials- OAuth client ID
  6. Choose:
    • Application type: Web application
    • Authorized redirect URI: http://localhost:8000/google/callback/
  7. Download the credentials.json file and place it in your Django project's root directory.

Step 3: Modify manage.py to Allow Insecure OAuth

To allow OAuth over HTTP (for development only), you must set an environment variable.

Set the OAUTHLIB_INSECURE_TRANSPORT variable in manage.py:

os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1' # Allow HTTP for OAuth (development only)

Add this inside the main() function before execute_from_command_line(...).

Step 4: Define Views to Handle Google OAuth and Gmail Fetching

Now let’s define views for login, callback, and email fetching.

1. home view

Displays a simple login link.

Python
def home(request): return HttpResponse("Welcome! <a href='/google/login/'>Login with Google</a>") 

2. google_login view

This initializes the OAuth2 flow and redirects users to the Google consent page.

Python
def google_login(request): flow = InstalledAppFlow.from_client_secrets_file(CLIENT_SECRETS_FILE, SCOPES) flow.redirect_uri = REDIRECT_URI authorization_url, state = flow.authorization_url(access_type='offline', prompt='consent') request.session['state'] = state # Store state in session return redirect(authorization_url) 

This view sets up the OAuth flow and redirects the user to Google's login/authorization page.

3. google_callback view

Handles the response from Google and fetches recent emails using the Gmail API.

Python
def google_callback(request): flow = Flow.from_client_secrets_file( CLIENT_SECRETS_FILE, scopes=SCOPES, redirect_uri=REDIRECT_URI, ) flow.fetch_token(authorization_response=request.build_absolute_uri()) credentials = flow.credentials service = build('gmail', 'v1', credentials=credentials) result = service.users().messages().list(userId='me', maxResults=5).execute() messages = result.get('messages', []) email_data = [] for msg in messages: msg_detail = service.users().messages().get(userId='me', id=msg['id']).execute() headers = msg_detail['payload'].get('headers', []) subject = next((h['value'] for h in headers if h['name'] == 'Subject'), 'No Subject') sender = next((h['value'] for h in headers if h['name'] == 'From'), 'Unknown') snippet = msg_detail.get('snippet', '') email_data.append({ 'subject': subject, 'sender': sender, 'snippet': snippet, }) return render(request, 'emails.html', {'emails': email_data}) 

This view processes the OAuth response, saves access credentials, and uses the Gmail API to fetch and display the user's latest 5 emails you can modify the number of emails fetched by changing maxResults parameter.

4. fetch_emails view

Allows accessing the emails again if valid credentials (token.json) already exist:

Python
def fetch_emails(request): creds = None if os.path.exists('token.json'): creds = Credentials.from_authorized_user_file('token.json', SCOPES) if not creds or not creds.valid: return HttpResponse("No valid credentials. Please log in first.") service = build('gmail', 'v1', credentials=creds) try: results = service.users().messages().list(userId='me', maxResults=5).execute() messages = results.get('messages', []) email_subjects = [] for message in messages: msg = service.users().messages().get(userId='me', id=message['id']).execute() snippet = msg.get('snippet', '(No snippet)') email_subjects.append(snippet) return HttpResponse('<br><br>'.join(email_subjects)) except Exception as e: return HttpResponse(f"An error occurred: {str(e)}") 

Complete code for gfg_auth_app/views.py

Python
from django.shortcuts import render, redirect import os import json from django.urls import reverse from google_auth_oauthlib.flow import InstalledAppFlow from googleapiclient.discovery import build from django.shortcuts import redirect from django.http import HttpResponse from django.conf import settings from google.auth.transport.requests import Request from google.oauth2.credentials import Credentials from google_auth_oauthlib.flow import Flow # Google OAuth2 client ID and secret CLIENT_SECRETS_FILE = os.path.join(settings.BASE_DIR, 'credentials.json') SCOPES = ['https://www.googleapis.com/auth/gmail.readonly'] REDIRECT_URI = 'http://localhost:8000/google/callback/' def home(request): return HttpResponse("Welcome! <a href='/google/login/'>Login with Google</a>") def google_login(request): flow = InstalledAppFlow.from_client_secrets_file(CLIENT_SECRETS_FILE, SCOPES) flow.redirect_uri = 'http://localhost:8000/google/callback/' authorization_url, state = flow.authorization_url(access_type='offline', prompt='consent') # Store the state in the session for later use request.session['state'] = state return redirect(authorization_url) def google_callback(request): flow = Flow.from_client_secrets_file( CLIENT_SECRETS_FILE, scopes=SCOPES, redirect_uri=REDIRECT_URI, ) flow.fetch_token(authorization_response=request.build_absolute_uri()) credentials = flow.credentials service = build('gmail', 'v1', credentials=credentials) # Fetch messages result = service.users().messages().list(userId='me', maxResults=5).execute() messages = result.get('messages', []) email_data = [] for msg in messages: msg_detail = service.users().messages().get(userId='me', id=msg['id']).execute() headers = msg_detail['payload'].get('headers', []) subject = next((h['value'] for h in headers if h['name'] == 'Subject'), 'No Subject') sender = next((h['value'] for h in headers if h['name'] == 'From'), 'Unknown') snippet = msg_detail.get('snippet', '') email_data.append({ 'subject': subject, 'sender': sender, 'snippet': snippet, }) return render(request, 'emails.html', {'emails': email_data}) def fetch_emails(request): creds = None if os.path.exists('token.json'): creds = Credentials.from_authorized_user_file('token.json', SCOPES) if not creds or not creds.valid: return HttpResponse("No valid credentials. Please log in first.") service = build('gmail', 'v1', credentials=creds) try: results = service.users().messages().list(userId='me', maxResults=5).execute() messages = results.get('messages', []) email_subjects = [] if not messages: email_subjects.append('No messages found.') else: for message in messages: msg = service.users().messages().get(userId='me', id=message['id']).execute() snippet = msg.get('snippet', '(No snippet)') email_subjects.append(snippet) return HttpResponse('<br><br>'.join(email_subjects)) except Exception as e: return HttpResponse(f"An error occurred: {str(e)}") 


Step 5: Create Template to Show Emails

This template will display the subject, sender, and snippet of each fetched email. If the templates folder does not exists in the gfg_auth_app folder then create one and in the templates folder, create an emails.html file and paste the following code:

HTML
<!DOCTYPE html> <html> <head> <title>Your Gmail Inbox</title> <style>  body {  font-family: Arial, sans-serif;  margin: 40px;  }  .email {  border: 1px solid #ccc;  padding: 12px;  margin-bottom: 15px;  border-radius: 6px;  }  .subject {  font-weight: bold;  color: #2c3e50;  }  .sender {  color: #555;  }  </style> </head> <body> <h1>Fetched Emails</h1> {% if emails %} {% for email in emails %} <div class="email"> <div class="subject">{{ email.subject }}</div> <div class="sender">From: {{ email.sender }}</div> <p>{{ email.snippet }}</p> </div> {% endfor %} {% else %} <p>No emails found.</p> {% endif %} </body> </html> 

Step 6: Define URL Patterns

Define URL patterns that map specific URL paths to the corresponding views created earlier. This is essential so Django knows how to route incoming requests. We'll create the URL configuration in our app and include it in the project's root configuration.

gfg_auth_app/urls.py:

Python
from django.urls import path from . import views urlpatterns = [ path('', views.home, name='home'), path('google/login/', views.google_login, name='google_login'), path('google/callback/', views.google_callback, name='google_callback'), path('google/emails/', views.fetch_emails, name='fetch_emails'), ] 

gfg_auth_project/urls.py:

Python
from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('', include('gfg_auth_app.urls')), ] 

Now, when users visit the app URLs, Django will call the right view functions accordingly.

Final Step: Run the Project

Start the development server using command:

python manage.py runserver

Output:

django15
Home page of the app

Clicking on the "Login with Google" hyperlink, we will be directed to login page:

django16
Login with Google

You can choose from the already logged in accounts or you can even use another account. After selecting the account click on allow button and you will be redirected to the page that will display the 5 most recent mails of the selected account:

django17
5 most recent mails

Similar Reads

Article Tags :
Practice Tags :