Gmail with FastAPI

9 min read

Introduction

In a world where technology moves at the speed of light, FastAPI is the newest package that provides developers with a quick setup, fast-network solution for controlling backend APIs. Its power and ease of use make this framework a top choice for web servers today. Coming loaded with a standard package of network controls, FastAPI provides pythonic methods for everything from routes and automatic model serialization to swagger generation.

In this tutorial, we will walk through a simple example of routing traffic through a backend web server to Gmail for managing a user’s messages. We will go over basic features of FastAPI such as routes, dependency injection, and the underlying Pydantic library. By the end, you will be ready to connect your local web server to the Google API or any other public web interface.

What Is FastAPI And Why Use It For Routing?

FastAPI has quickly become the go-to library for creating web servers in Python. It offers a full package of network tools including simple-to-use router annotations, CORS middleware, serialization, and automated swagger docs. Under the hood, FastAPI leverages both Pydantic and Uvicorn to host endpoints and serialize objects at speeds that are considerably faster than Flask and Django, older options for web hosting. Don’t believe it? Check out TechEmpower for benchmarking Python server technologies.

According to the Python Developer Survey, FastAPI became the most-downloaded Python web framework as of August 2025, growing from 29% to 38% adoption over the past year — more than 4M downloads a day, per FastAPI’s own announcement. Given these numbers, FastAPI proves itself to be the optimal choice for serving backend data connections in Python. So, without further ado, let’s start up a server and connect with Gmail.

Setting Up FastAPI

To get started, let’s install the underlying dependencies in our Python environment.

pip install pydantic uvicorn fastapi

These three dependencies are all you need to spin up a local server and start hosting your API with automatic object serialization and even an autogenerated swagger doc as a freebie.

Now, to create the server, open a new file in your Python directory and call it fastapi-server.py. FastAPI works on the standard model where your main block will start up a server which takes a FastAPI object loaded with all your custom configurations.

In the following code, we use the uvicorn dependency we just installed as the core server, serving on localhost at port 8000.

from fastapi import FastAPI

app = FastAPI()

if __name__ == '__main__':
    import uvicorn
    uvicorn.run(
        "fastapi-server:app",
        host="localhost",
        port=8000,
        reload=True
    )

This code doesn’t do much, but it will serve as the foundation for our entire application. For a local app we run with reload=True in uvicorn; it’s important to note that production applications will not use this. Now let’s add some routers.

Defining Simple Routers And Pydantic Models

Working with FastAPI, we use the primary app object we’ve created and add all desired routes and configurations to it, so that the uvicorn server can run it all in concert. For example, if we want to add a simple “health” endpoint to our server, we create an APIRouter object defining a health endpoint and add it to our application.

from fastapi import FastAPI, APIRouter

app = FastAPI()
health_router = APIRouter()

@health_router.get("/health")
def health_check():
    return {"status": "ok"}

app.include_router(health_router)

if __name__ == '__main__':
    import uvicorn
    uvicorn.run(
        "fastapi-server:app",
        host="localhost",
        port=8000,
        reload=True
    )

In the above example, we built a /health endpoint onto the health_router, specifying the HTTP method as GET. This route simply responds with a dictionary showing our status is “ok” — a common practice in web servers. Note that Pydantic does all the work of serialization here: we didn’t have to define any serializers to stream this response across the network. It’s connected out of the box to return a valid HTTP response from the endpoint regardless of what we send back.

Let’s expand on this by creating a new Gmail endpoint to read the number of messages a user has in their mailbox.

To simplify HTTP calls to the Gmail API, we’ll use Google’s Python libraries. Install the following dependencies in your Python environment to get started:

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

These libraries help us configure OAuth 2.0 credentials and build a Gmail client. This configuration requires you to go to the Google Developer portal and set up your app to obtain the client ID and client secret values. Walking through that process is a large topic on its own, so I’ll cover it in another tutorial. For now, I’ll assume you have the client credentials in a file named credentials.json.

Now let’s add a new gmail_router object with the path prefix="/gmail". Here we host the path /inbox, where we serve clients their email address and message count. Then we add our new endpoint to the app object via gmail_router.

from fastapi import APIRouter, Depends, HTTPException
from google.oauth2.credentials import Credentials
from googleapiclient.discovery import build

def get_gmail_service():
    # Load credentials from file or environment
    creds = Credentials.from_authorized_user_file("credentials.json", [
        "https://www.googleapis.com/auth/gmail.readonly"
    ])
    service = build("gmail", "v1", credentials=creds)
    return service

gmail_router = APIRouter(prefix="/gmail")

@gmail_router.get("/inbox")
def read_inbox(service=Depends(get_gmail_service)):
    try:
        profile = service.users().getProfile(userId="me").execute()
        messages = service.users().messages().list(userId="me").execute()
        message_count = messages.get("resultSizeEstimate", 0)
        return {
            "email": profile["emailAddress"],
            "message_count": message_count
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

app.include_router(gmail_router)

We now have a simple API server that can provide a user with Gmail connectivity. From here, we can scale up our application to whatever limits we want. The libraries provided by Google contain a whole host of endpoints for communicating with Gmail, which can be leveraged for all sorts of projects to manage or automate a user’s email.

Dependency Injection For Singletons

Now let’s talk about some of the technical configuration in FastAPI that abstracts away most of the usual REST or Python plumbing.

Notice above that read_inbox() takes a service parameter, which is the return value of FastAPI’s Depends(). Depends handles dependency injection: it requires its argument to be a pre-defined function returning an object of matching type, like we did with get_gmail_service().

Dependency injection matters in asynchronous web hosting for several reasons, including providing a singleton pattern for creating objects like our Gmail service. Python doesn’t enforce this pattern — we could still instantiate the service object some other way — but FastAPI’s Depends gives us a framework that’s easily repeatable.

This pattern also makes it easier to follow the flow of data through your API, since the dependency structure is defined throughout your project. Circular dependencies cause runtime errors, which enforces a single direction for object creation. This leads to better scalability by reducing cognitive complexity and making for cleaner code. Dependency injection and singletons should be the default in production-ready asynchronous APIs.

Handling Origin Security With CORS Middleware

Before we move on, let’s briefly cover CORS middleware and some security concepts. Browsers typically limit cross-origin requests: if a frontend page is hosted at one location and requests data from another, the browser discontinues the request. This is the “same-origin policy,” which lets the browser halt potentially malicious attacks against your server, an attack class known as cross-site scripting (XSS). Since this is the default for browsers, we need a mechanism to allow cross-origin resource sharing (CORS). Browsers that enforce same-origin policy add an Origin header in a preflight check when requesting resources from a separate domain, and expect the server to respond with an allow list for the request. If that passes, the browser moves forward. This preflight and allow list is standard browser-server communication, so let’s add one more piece of configuration to our FastAPI server:

from fastapi.middleware.cors import CORSMiddleware

app.add_middleware(
    CORSMiddleware,
    allow_origins=["localhost:8000"],  # Adjust as needed
    allow_credentials=True,  # Allow cookies and authorization headers
    allow_methods=["GET", "POST", "DELETE"],  # Allow specific HTTP methods
    allow_headers=["*"],  # Allow all headers
)

Here we’ve added a middleware to our app object. Our server can now work together with a browser to list the domains we expect to request our data from. This would help if, for example, your browser loaded a dashboard hosted at localhost:8000 while your app itself was hosted in the cloud at somewhere.net.

Note that this does not directly secure your server, nor does it prevent other clients from calling your API — that requires actual authentication. CORS only works in conjunction with a properly configured browser.

Read more on this topic on MDN’s CORS guide.

With the configuration done, let’s check out the automatically generated swagger docs.

Automatic Swagger Documentation

After finishing your API service, it’s always important to document it so others know how to use it — and FastAPI provides these docs out of the box. Run your server application and point your browser to http://localhost:8000/docs.

This route takes you to a Swagger page generated automatically from the routes on your app object, and it updates as you build more endpoints, add parameters, or change the configuration on app.

Conclusion And Next Steps

After following along with this tutorial, you’ve built a simple API server that can host a user’s Gmail account. We covered core FastAPI concepts like routers and models, dependency injection and singletons, CORS, and Swagger docs. With these basics, you’re ready to automate email processing or connect to other APIs like Meta or Reddit.

In a future post, I’ll cover the Gmail application setup in more depth, since the Google developer dashboard can be daunting. In the meantime, reach out and let me know what you thought — thanks for reading TechNoise!

References And Further Reading