feat(gmail-single-user): new single-mailbox Gmail integration
Gmail for one mailbox over OAuth 2.0 (no service account / delegation): auth-link + exchange-code to obtain a refresh token, connectivity test, message search/get, send/reply with attachments, attachment retrieval, and get_incidents ingestion with an OCSF mapper. Refresh-token grant, stdlib-only (no extra Python dependencies). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
import json, os, sys, urllib.parse, urllib.request, urllib.error
|
||||
|
||||
SCOPES = (
|
||||
"https://www.googleapis.com/auth/gmail.readonly "
|
||||
"https://www.googleapis.com/auth/gmail.compose "
|
||||
"https://www.googleapis.com/auth/gmail.send"
|
||||
)
|
||||
|
||||
|
||||
def _cfg():
|
||||
return json.loads(os.environ.get("INTEGRATION_SECRETS", "{}"))
|
||||
|
||||
|
||||
def main():
|
||||
cfg = _cfg()
|
||||
client_id = str(cfg.get("client_id") or "")
|
||||
if not client_id:
|
||||
raise Exception("client_id is not set")
|
||||
url_params = {
|
||||
"client_id": client_id,
|
||||
"redirect_uri": str(cfg.get("redirect_uri") or "http://localhost"),
|
||||
"response_type": "code",
|
||||
"scope": SCOPES,
|
||||
"access_type": "offline",
|
||||
"prompt": "consent",
|
||||
}
|
||||
if cfg.get("email"):
|
||||
url_params["login_hint"] = cfg["email"]
|
||||
link = "https://accounts.google.com/o/oauth2/v2/auth?" + urllib.parse.urlencode(url_params)
|
||||
print(json.dumps({
|
||||
"auth_link": link,
|
||||
"next": "Open the link, approve access, copy the 'code' from the redirect, then run gmail-single-user-exchange-code.",
|
||||
}))
|
||||
|
||||
|
||||
try:
|
||||
main()
|
||||
except urllib.error.HTTPError as e:
|
||||
print(json.dumps({"error": "HTTP " + str(e.code), "detail": e.read().decode("utf-8", "replace")}))
|
||||
sys.exit(1)
|
||||
except Exception as e:
|
||||
print(json.dumps({"error": str(e)}))
|
||||
sys.exit(1)
|
||||
Reference in New Issue
Block a user