Skip to content

Feature: Export Gmail filters in WebUI-compatible XML format #174

@gwpl

Description

@gwpl

🤖 This issue was co-created in collaboration between a Human and an AI Assistant (Claude Opus 4.5). The human had the brilliant idea; the AI did the tedious research, format reverse-engineering, and documentation. Together we make a decent team! 🧑‍💻

Update: Issue revised with verified sources and real-world XML examples.


Summary

Add ability to export Gmail filters in the Atom XML format that Gmail WebUI can import, enabling users to:

  1. Share filter configurations between Gmail accounts
  2. Distribute standardized filter sets within teams
  3. Backup filters in a format that can be restored via Gmail Settings UI

Current State

gogcli currently supports:

gog gmail filters list          # JSON or table output (API format)
gog gmail filters get <id>      # Single filter details
gog gmail filters create        # Create new filter
gog gmail filters delete <id>   # Delete filter

Problem: The --json output uses Gmail API's JSON format, which is incompatible with Gmail's WebUI import feature (Settings → Filters → Import filters).

Proposed Solution

# Export all filters to WebUI-compatible XML
gog gmail filters export > mailFilters.xml

# Export specific filters by ID (optional enhancement)
gog gmail filters export --id=ABC123 > selected.xml

Technical Details

XML Format (Verified from Real Exports)

Gmail uses Atom Syndication Format (RFC 4287) with Google Apps namespace. Format verified from actual Gmail exports:

Real example from clouserw/gmailfilters (2009):

<?xml version='1.0' encoding='UTF-8'?>
<feed xmlns='http://www.w3.org/2005/Atom' xmlns:apps='http://schemas.google.com/apps/2006'>
    <title>Mail Filters</title>
    <id>tag:mail.google.com,2008:filters:1206327421108,1228202452022</id>
    <updated>2009-12-09T20:44:01Z</updated>
    <author>
        <name>Wil Clouser</name>
        <email>clouserw@gmail.com</email>
    </author>
    <entry>
        <category term='filter'></category>
        <title>Mail Filter</title>
        <id>tag:mail.google.com,2008:filter:1206327421108</id>
        <updated>2009-12-09T20:44:01Z</updated>
        <content></content>
        <apps:property name='from' value='bugzilla-daemon@mozilla.org'/>
        <apps:property name='to' value='clouserw@gmail.com'/>
        <apps:property name='hasTheWord' value='blocker'/>
        <apps:property name='label' value='blocker'/>
    </entry>
</feed>

Real example from dimagi/gmail-filters (2014):

<entry>
    <category term='filter'></category>
    <title>Mail Filter</title>
    <id>tag:mail.google.com,2008:filter:1286460749536</id>
    <updated>2014-09-19T17:40:28Z</updated>
    <content></content>
    <apps:property name='from' value='noreply@github.com'/>
    <apps:property name='label' value='github'/>
    <apps:property name='shouldArchive' value='true'/>
</entry>

Real example from dims' Kubernetes filters (2022):

<entry>
    <category term='filter'></category>
    <title>Mail Filter</title>
    <id>tag:mail.google.com,2008:filter:1463531420708</id>
    <updated>2022-06-25T21:39:52Z</updated>
    <content></content>
    <apps:property name='hasTheWord' value='list:"kubernetes-dev@googlegroups.com"'/>
    <apps:property name='label' value='kubernetes'/>
    <apps:property name='shouldArchive' value='true'/>
    <apps:property name='sizeOperator' value='s_sl'/>
    <apps:property name='sizeUnit' value='s_smb'/>
</entry>

Property Names (Verified from gmailctl source)

Criteria:

  • from, to, subject - Address/text matching
  • hasTheWord - Gmail search query syntax
  • doesNotHaveTheWord - Negative query

Actions:

  • label - Apply label (by name)
  • shouldArchive - Skip inbox (true)
  • shouldMarkAsRead - Mark read (true)
  • shouldTrash - Delete (true)
  • shouldNeverSpam - Never spam (true)
  • shouldStar - Star (true)
  • shouldAlwaysMarkAsImportant / shouldNeverMarkAsImportant - Importance
  • forwardTo - Forward address
  • smartLabelToApply - Category tab (^smartlabel_personal, ^smartlabel_social, etc.)

Size filtering (from dims' export):

  • sizeOperator - s_sl (larger) or s_ss (smaller)
  • sizeUnit - s_sb (bytes), s_skb (KB), s_smb (MB)

API → XML Conversion Required

API JSON XML Property Notes
criteria.from from Direct
criteria.query hasTheWord Direct
action.addLabelIds label Requires label ID→name lookup
action.removeLabelIds["INBOX"] shouldArchive='true' Semantic conversion
action.removeLabelIds["UNREAD"] shouldMarkAsRead='true' Semantic conversion

Key implementation detail: API returns label IDs (e.g., Label_123), XML requires label names. Must call users.labels.list to build mapping.

Related Work

gmailctl already implements XML export:

This proves the format is well-understood and implementable.

Use Cases

  1. Team filter sharing - Export curated filters, share via wiki/docs
  2. Account migration - Backup filters in portable format
  3. Version control - Track filter changes in git

References

Official

Verified Real-World XML Exports

Implementation Reference

Format Analysis

Acceptance Criteria

  • gog gmail filters export outputs valid Atom XML
  • XML can be imported via Gmail Settings → Import filters
  • Label names resolved from IDs via users.labels.list
  • System labels converted (STARREDshouldStar, etc.)
  • Special characters XML-escaped ("&quot;)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions