{"id":37976014,"url":"https://github.com/answerdotai/solvemail","last_synced_at":"2026-01-20T09:00:42.661Z","repository":{"id":332483023,"uuid":"1133386857","full_name":"AnswerDotAI/solvemail","owner":"AnswerDotAI","description":"Gmail / Google Workspace email client built on the Gmail API","archived":false,"fork":false,"pushed_at":"2026-01-17T20:03:45.000Z","size":180,"stargazers_count":7,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-19T13:53:40.848Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AnswerDotAI.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-13T09:23:55.000Z","updated_at":"2026-01-19T01:21:15.000Z","dependencies_parsed_at":"2026-01-19T08:02:13.474Z","dependency_job_id":null,"html_url":"https://github.com/AnswerDotAI/solvemail","commit_stats":null,"previous_names":["answerdotai/solvemail"],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/AnswerDotAI/solvemail","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AnswerDotAI%2Fsolvemail","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AnswerDotAI%2Fsolvemail/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AnswerDotAI%2Fsolvemail/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AnswerDotAI%2Fsolvemail/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AnswerDotAI","download_url":"https://codeload.github.com/AnswerDotAI/solvemail/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AnswerDotAI%2Fsolvemail/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28599827,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-20T08:51:33.170Z","status":"ssl_error","status_checked_at":"2026-01-20T08:51:10.855Z","response_time":117,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-01-16T18:30:31.350Z","updated_at":"2026-01-20T09:00:42.581Z","avatar_url":"https://github.com/AnswerDotAI.png","language":"Python","readme":"# solvemail\n\nA simple Gmail / Google Workspace email client built on the official Gmail API, using the fastai/fastcore coding style.\n\n## Install\n\n```bash\npip install solvemail\n```\n\nOr for development:\n\n```bash\npip install -e .\n```\n\n## OAuth setup\n\nFor detailed instructions on setting up Google Cloud credentials, see [ezgmail's excellent documentation](https://github.com/asweigart/ezgmail#enable-the-gmail-api).\n\nIn brief:\n\n1. Create an OAuth Client ID (Desktop app) in [Google Cloud Console](https://console.cloud.google.com) and enable the Gmail API\n2. Download the client secrets JSON as `credentials.json`\n3. Put `credentials.json` next to your script (or pass its path)\n\nOn first run, `solvemail` will open a browser to authorize and will save `token.json`.\n\n## Quick start\n\n```python\nimport solvemail\n\nsolvemail.init()  # reads credentials.json + token.json in cwd\n\n# For multiple accounts, use separate token files:\n# solvemail.init(token_path='work.json')    # first run opens browser to auth\n# solvemail.init(token_path='personal.json') # switch account without re-auth\n\n# Check which account you're using\nsolvemail.profile().email\n\n# solvemail exports the key API functionality through wildcard import\nfrom solvemail import *\n\n# Search for threads\nthreads = search_threads('is:unread newer_than:7d', max_results=10)\n\n# Get thread details\nt = threads[0]\nfor m in t.msgs():\n    print(m.frm, '|', m.subj)\n\n# Read a message\nm = t.msgs()[0]\nm.subj, m.frm, m.snip, m.text()\n\n# Send an email\nsend(to='someone@example.com', subj='Hello', body='Hi there!')\n\n# Create and send a reply\ndraft = t.reply_draft(body='Thanks!')\ndraft.send()\n```\n\n## Features\n\n### Searching\n\n```python\n# Search threads (conversations)\nsearch_threads('from:boss@company.com', max_results=20)\n\n# Search individual messages\nsearch_msgs('has:attachment filename:pdf', max_results=100)\n```\n\n### Messages\n\n```python\nm = msg(id)           # Fetch by id\nm.subj, m.frm, m.to             # Headers\nm.text(), m.html()              # Body content\nm.mark_read(), m.mark_unread()  # Read status\nm.star(), m.unstar()            # Starred\nm.archive()                     # Remove from inbox\nm.trash(), m.untrash()          # Trash\nm.add_labels('MyLabel')         # Add labels\nm.rm_labels('INBOX')            # Remove labels\n```\n\n### Threads\n\n```python\nt = thread(id)        # Fetch by id\nt.msgs()                        # List messages\nt[0], t[-1]                     # Index into messages\nt.reply_draft(body='...')       # Create reply draft\nt.reply(body='...')             # Send reply directly\n\n# Batch fetch multiple threads efficiently (one HTTP call)\nthreads = search_threads('in:inbox', max_results=50)\nthreads = get_threads(threads)\n```\n\n### Message display\n\nMessages render nicely in Jupyter notebooks (quotes and signatures stripped automatically).\n\n```python\nm = t[-1]\nm.body()   # Cleaned text (no quotes/signatures)\nm.html()   # HTML body (falls back to text wrapped in \u003cpre\u003e)\n\n# View message with headers (as dict or plain text)\nview_msg(m.id)                      # Returns dict with headers + body\nview_msg(m.id, as_json=False)       # Returns formatted text\n\n# View full thread\nview_thread(t.id)                   # Dict of msgid -\u003e msg dict\nview_thread(t.id, as_json=False)    # Concatenated text with separators\n```\n\n### Inbox helpers\n\n```python\nview_inbox(max_msgs=20)             # Batch fetch inbox messages\nview_inbox_threads(max_threads=20)  # Batch fetch inbox threads\nview_inbox(unread=True)             # Only unread\n```\n\n### Labels\n\n```python\nlabels()                        # List all labels\nlabel('INBOX')                  # Get by name or id\nfind_labels('project')          # Search labels\ncreate_label('My Label')        # Create new label\n```\n\n### Drafts\n\n```python\ndrafts()                        # List drafts\ncreate_draft(to='...', subj='...', body='...')\nreply_to_thread(thread_id, body='...')\n```\n\n### Bulk operations\n\n```python\n# Batch modify labels (auto-chunks, no 1000 message limit)\nids = [m.id for m in search_msgs('in:inbox')]\nbatch_label(ids, add=['SPAM'], rm=['INBOX'])\n\n# Trash multiple messages\ntrash_msgs(ids)\n\n# Permanently delete (requires full mail scope)\nbatch_delete(ids)\n```\n\n## Testing\n\nSet these env vars to run e2e tests against a throwaway Gmail/Workspace account:\n\n- `GMAILX_CREDS` — path to `credentials.json`\n- `GMAILX_TOKEN` — path to `token.json` (will be created if missing)\n- `GMAILX_E2E` — set to `1` to enable e2e tests\n\n```bash\npytest -q\n```\n\n## Credits\n\nInspired by [ezgmail](https://github.com/asweigart/ezgmail) by [Al Sweigart](https://inventwithpython.com/) — thanks Al for the great work! The ezgmail repo also has excellent documentation on setting up Gmail API credentials.\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanswerdotai%2Fsolvemail","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fanswerdotai%2Fsolvemail","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanswerdotai%2Fsolvemail/lists"}