How to Batch Modify Gmail Labels with gogcli: Commands and Code Examples
Use the gog gmail batch modify command with --add and --remove flags to modify labels on multiple messages via a single API call, automatically resolving label names to IDs.
The steipete/gogcli repository provides a command-line interface for managing Gmail programmatically. Batch modifying Gmail labels with gogcli allows you to efficiently add or remove labels from hundreds of messages without exhausting API quotas through individual calls.
How gogcli Implements Batch Label Modification
The batch modify functionality resides in the internal/cmd package and executes label changes through a single Gmail API request. This approach minimizes network overhead and respects Google's rate limits by bundling operations.
Parsing Arguments and CSV Labels
In internal/cmd/gmail_batch.go, the GmailBatchModifyCmd function handles argument parsing. It collects message IDs from positional arguments and processes the --add and --remove flags using the splitCSV helper defined in internal/cmd/csv.go.
This design allows you to specify multiple labels as comma-separated values:
--add=Work,Urgent --remove=Spam,Promotions
Resolving Label Names to IDs
Gmail's API requires label IDs, not display names. The fetchLabelNameToID function in internal/cmd/gmail_labels.go retrieves the complete label mapping, while resolveLabelIDs in internal/cmd/gmail_labels_utils.go converts user-supplied names to their canonical IDs, falling back to raw values if no match exists.
This resolution happens automatically, allowing you to use familiar names like "Important" while the tool handles the underlying "Label_123" identifiers.
Executing the BatchModify API Call
Once resolved, the command invokes svc.Users.Messages.BatchModify at lines 119-128 of internal/cmd/gmail_batch.go. This sends a single HTTP request to Gmail's batchModify endpoint containing all message IDs and label modifications.
The operation is atomic from the client's perspective—either all specified modifications succeed in one network round-trip, or the command reports the failure.
Dry-Run and Output Formatting
The implementation respects the global --dry-run flag via the dryRunExit helper, echoing the intended operation without modifying data. Output formatting is handled conditionally: when --json is specified, the command emits structured JSON via WriteJSON in internal/outfmt/outfmt.go; otherwise, it prints a human-friendly count of affected messages.
Practical Code Examples
Basic Batch Modification
Add the "Important" label and remove the "Newsletters" label from three specific messages:
gog gmail batch modify \
--add=Important \
--remove=Newsletters \
17c2a3f4b5d6e7f8 23d5b7c9e1a2f3g4 9a8b7c6d5e4f3g2h1
The --add and --remove flags accept comma-separated lists or single values. The command resolves "Important" and "Newsletters" to their Gmail IDs before sending the batch request.
Using Label IDs Directly
When you already know the internal label IDs, specify them to skip the name lookup step:
gog gmail batch modify \
--add=Label_123456 \
--remove=Label_987654 \
$(cat ids.txt)
This approach avoids the extra Labels.List API call, making it faster for bulk operations where you have cached the label mappings.
Dry-Run to Preview Operations
Verify your command before executing it:
gog --dry-run gmail batch modify \
--add=Work,Personal \
--remove=Spam \
1a2b3c4d5e6f7g8h9i0j
Output when using --json:
{
"message_ids": ["1a2b3c4d5e6f7g8h9i0j"],
"add": ["Work","Personal"],
"remove": ["Spam"]
}
No changes are sent to Gmail; this helps verify CSV parsing and label resolution.
Mixing Names and IDs
You can combine human-readable names with raw label IDs in the same command:
gog gmail batch modify \
--add=Label_123456,ProjectX \
--remove=Inbox \
5f6e7d8c9b0a1b2c3d4e
ProjectX is resolved to its ID, while Label_123456 is used unchanged.
Key Source Files and Functions
| File | Role | Relevant Sections |
|---|---|---|
internal/cmd/gmail_batch.go |
Implements the batch-modify and batch-delete commands. | GmailBatchModifyCmd.Run (label parsing, API call) |
internal/cmd/csv.go |
Utility for splitting CSV strings into slices. | splitCSV |
internal/cmd/gmail_labels_utils.go |
Helper for converting human-readable label names to Gmail IDs. | resolveLabelIDs |
internal/cmd/gmail_labels.go |
Retrieves the full label map from Gmail (ID ↔︎ name). | fetchLabelNameToID |
internal/outfmt/outfmt.go |
Formats command output (JSON vs. plain text). | IsJSON, WriteJSON |
internal/ui/ui.go |
Handles UI printing and error handling. | ui.FromContext calls used throughout |
These files provide the end-to-end flow: CLI flag parsing → CSV splitting → label resolution → batch API request → formatted output.
Summary
- Single API call efficiency: The
gog gmail batch modifycommand bundles multiple label operations into oneBatchModifyrequest, conserving Gmail API quota. - Automatic label resolution: Human-readable names are automatically converted to Gmail label IDs via
fetchLabelNameToIDandresolveLabelIDs, though raw IDs are also accepted. - Safety features: The global
--dry-runflag lets you preview changes without executing them, while--jsonprovides machine-readable output. - Flexible input: Labels can be specified as comma-separated values, and message IDs can be passed as arguments or piped from files.
Frequently Asked Questions
Can I use label names instead of IDs with gogcli batch modify?
Yes, gogcli accepts human-readable label names via the --add and --remove flags. The resolveLabelIDs function in internal/cmd/gmail_labels_utils.go automatically converts these names to Gmail's internal label IDs before making the API call, falling back to the raw value if no match is found.
Does gogcli support dry-run mode for batch label operations?
Yes, the global --dry-run flag is fully supported by the batch modify command. When enabled, the dryRunExit helper in internal/cmd/gmail_batch.go prints the intended operation as JSON or plain text without actually calling the Gmail API, allowing you to verify your command before execution.
How many messages can I modify in a single batch command?
While gogcli itself does not enforce a hard limit, the underlying Gmail API typically allows batch operations on hundreds of messages per request. You should pass all target message IDs as positional arguments to the gog gmail batch modify command, and the tool will process them in a single BatchModify API call.
What happens if a label name cannot be resolved?
If a label name cannot be resolved to an existing ID, the resolveLabelIDs function falls back to using the raw value provided. This allows you to specify label IDs directly, but means typos in label names may result in API errors rather than client-side validation failures.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →