Taming Gmail Filters with Terraform

From chaos to clarity: codifying Gmail labels and filters

· 5 min read

Email filters often pile up quietly in Gmail, making it tricky to recall why each one exists or how they interact. I use Terraform to bring order by putting Gmail labels and filters in version control, letting you tweak your inbox setup with confidence. The yamamoto-febc/gmailfilter provider works with both labels and filters, so you can handle everything in one place.

Get the Code

I open-sourced MailPilot on GitHub: 👉 https://github.com/eddyvlad/mailpilot

Clone or fork the repository to start with a working skeleton that already includes common modules. From there you can:

This way you can get going quickly without writing everything from scratch.

I called this project MailPilot.

Why Terraform for Gmail?

Terraform is usually for cloud infrastructure, yet it shines whenever you want reproducible, declarative configuration. Treating Gmail settings as code gives you:

Gmail filter settings page showing multiple filters in the default UI
Terraform turns this messy Gmail filters into clean, maintainable code.

Step-by-Step Setup

1. Install the Tools

2. Enable the Gmail API and Create OAuth Credentials

  1. Visit the Google Cloud Console.
  2. Create or pick a project.
  3. Enable Gmail API.
    Official documentation: Enabling the Gmail API.
Google Cloud Console interface with the Gmail API highlighted and enabled for a project.
Enabling the Gmail API in Google Cloud Console.
  1. Under APIs & Services → Credentials, create an OAuth client of type Desktop app.
  2. Download the client_secret_*.json file, store it at ~/.config/mailpilot/client_secret_mailpilot.json, and run chmod 600 to restrict access.
Google Cloud Console credentials page showing OAuth 2.0 Client ID setup for a desktop app.
Creating and downloading OAuth client credentials.

3. Authenticate with Application Default Credentials

bash
gcloud auth application-default login \
  --client-id-file ~/.config/mailpilot/client_secret_mailpilot.json \
  --scopes https://www.googleapis.com/auth/cloud-platform,https://www.googleapis.com/auth/gmail.labels,https://www.googleapis.com/auth/gmail.settings.basic
Terminal running gcloud auth application-default login with success message.
Authenticating Gmail access using gcloud.

This opens a browser for consent and saves your tokens locally. ⚠️ Tokens usually expire after seven days. Re-run this command whenever you want to apply new changes after that.

Quick sanity check:

bash
TOKEN="$(gcloud auth application-default print-access-token)"
curl -H "Authorization: Bearer $TOKEN" \
  https://gmail.googleapis.com/gmail/v1/users/me/labels

You should see JSON listing existing labels.

4. Scaffold the Terraform Project

bash
mkdir mailpilot
cd mailpilot
nano main.tf   # or use your preferred editor

Paste in a minimal configuration:

hcl
# terraform.tf
terraform {
  required_providers {
    gmailfilter = {
      source  = "yamamoto-febc/gmailfilter"
      version = "1.1.0"
    }
  }
}
 
provider "gmailfilter" {}
 
# main.tf
resource "gmailfilter_label" "newsletters" {
  name = "Newsletters"
}
 
resource "gmailfilter_filter" "nl_archive" {
  criteria {
    from           = "news@newsletter.example"
    exclude_chats  = false
    has_attachment = false
  }
  action {
    add_label_ids    = [gmailfilter_label.newsletters.id]
    remove_label_ids = ["INBOX", "SPAM"]
  }
}

This file declares the Gmail provider, a label named Newsletters, and a filter that tags and archives emails from news@newsletter.example. Terraform stores state locally in terraform.tfstate.

Project directory tree showing main.tf and terraform.tfstate files.
Basic Terraform project structure for MailPilot.

5. Initialize and Apply

bash
terraform init
terraform plan
terraform apply

Check Gmail afterward to see the new label and filter in action.

Terminal output from terraform plan showing planned creation of Gmail labels and filters.
Terraform plan previewing new Gmail label and filter resources.
Gmail inbox with a new Newsletters label applied to incoming messages.
Gmail inbox after applying the Newsletters label with Terraform.

Going Further with Modules and Loops

Once you are comfortable with the basics, you can modularize recurring rules. For example, MailPilot’s receipts module uses a for_each loop over a map of senders:

hcl
# modules/receipts/filters.tf
locals {
  criterias = {
    shopee = { query = "from:shopee subject:\"Your payment has been confirmed\"" }
    github = { query = "from:github subject:\"Payment Receipt\"" }
    # more entries...
  }
}
 
resource "gmailfilter_filter" "receipts" {
  for_each = local.criterias
 
  action {
    add_label_ids    = [var.label_id]
    remove_label_ids = ["INBOX", "SPAM"]
  }
 
  criteria {
    exclude_chats  = "false"
    has_attachment = "false"
    query          = lookup(each.value, "query", null)
  }
}
 
# modules/receipts/variables.tf
variable "label_id" {
  type        = string
  description = "ID of the Receipts label"
}
 
# modules/receipts/versions.tf
terraform {
  required_providers {
    gmailfilter = {
      source  = "yamamoto-febc/gmailfilter"
      version = "1.1.0"
    }
  }
}
 
# main.tf
module "receipts_filter" {
  source   = "./modules/receipts-filter"
  label_id = gmailfilter_label.receipts.id
}

Adding a new sender is as simple as appending another entry to criterias. Terraform generates one filter per entry, keeping the configuration concise and consistent.

The same provider also manages labels, so you can create nested structures like Receipts/Transport without leaving your editor.

Project directory tree showing modules folder with receipts submodule for Gmail filters.
Organizing filters with reusable modules.

Final Thoughts

MailPilot shows that even a personal inbox can benefit from infrastructure as code. With a bit of Terraform and the Gmail provider, you can:

If your Gmail filters feel out of control, try codifying them. Start with a single label and filter; once you see how approachable it is, you may find yourself managing email as if it were any other part of your infrastructure. With MailPilot, your Gmail filters become readable, shareable, and maintainable.