# Gmail-regels beheren via de API [[TOC]] ## Gmail-filters via de API Gmail-filters zijn automatische regels die acties uitvoeren op inkomende e-mails. Via de Gmail API kun je filters programmatisch beheren. Dat is handig voor het uitrollen van standaardfilters naar meerdere gebruikers, het importeren van filters uit een configuratiesysteem of het automatisch aanpassen van filters op basis van bedrijfslogica. :::info title="Welke scope heb je nodig?" Alle bewerkingen op filters (lezen, aanmaken en verwijderen) gebruiken dezelfde scope: `https://www.googleapis.com/auth/gmail.settings.basic`. Voor het beheren van labels heb je daarnaast `https://www.googleapis.com/auth/gmail.labels` nodig. Beide scopes worden door Google als gevoelig (sensitive) geclassificeerd, dus voor een productie-app is een Google-verificatie van je OAuth-consent-scherm vereist. ::: ## Authenticatie ```python from google.oauth2.credentials import Credentials from google_auth_oauthlib.flow import InstalledAppFlow from googleapiclient.discovery import build import os SCOPES = [ 'https://www.googleapis.com/auth/gmail.settings.basic', 'https://www.googleapis.com/auth/gmail.labels', ] def get_gmail_service(): creds = None if os.path.exists('token.json'): creds = Credentials.from_authorized_user_file('token.json', SCOPES) if not creds or not creds.valid: flow = InstalledAppFlow.from_client_secrets_file('credentials.json', SCOPES) creds = flow.run_local_server(port=0) with open('token.json', 'w') as token: token.write(creds.to_json()) return build('gmail', 'v1', credentials=creds) ``` ## Bestaande filters ophalen ```python def haal_filters_op(service): result = service.users().settings().filters().list(userId='me').execute() filters = result.get('filter', []) for f in filters: criteria = f.get('criteria', {}) action = f.get('action', {}) print(f'Filter ID: {f["id"]}') print(f' Van: {criteria.get("from", "Niet ingesteld")}') print(f' Onderwerp bevat: {criteria.get("subject", "Niet ingesteld")}') print(f' Acties: {action}') print('---') return filters ``` ## Een filter aanmaken Een filter bestaat uit twee delen: `criteria` (waar het filter op matcht) en `action` (wat er moet gebeuren). Acties verwijzen naar label-id's, niet naar labelnamen, dus zoek de id eerst op of maak het label aan. ```python def maak_filter_aan(service, van=None, onderwerp=None, label_naam=None, archiveren=False, markeer_gelezen=False, verwijderen=False): criteria = {} if van: criteria['from'] = van if onderwerp: criteria['subject'] = onderwerp add_labels = [] remove_labels = [] if label_naam: label_id = haal_of_maak_label(service, label_naam) add_labels.append(label_id) if archiveren: remove_labels.append('INBOX') if markeer_gelezen: remove_labels.append('UNREAD') if verwijderen: add_labels.append('TRASH') filter_body = { 'criteria': criteria, 'action': { 'addLabelIds': add_labels, 'removeLabelIds': remove_labels } } result = service.users().settings().filters().create( userId='me', body=filter_body ).execute() print(f'Filter aangemaakt: {result["id"]}') return result['id'] def haal_of_maak_label(service, naam): labels = service.users().labels().list(userId='me').execute() for label in labels.get('labels', []): if label['name'] == naam: return label['id'] nieuw_label = service.users().labels().create( userId='me', body={'name': naam, 'labelListVisibility': 'labelShow', 'messageListVisibility': 'show'} ).execute() return nieuw_label['id'] ``` ## Filters in bulk aanmaken Voor het uitrollen van een vaste set filters is het handig om de configuratie los van de code te houden, bijvoorbeeld in een JSON- of YAML-bestand. Zo kunnen niet-ontwikkelaars de filters aanpassen zonder de code te raken. ```python def importeer_filters_vanuit_config(service, filter_configuraties): resultaten = [] for config in filter_configuraties: filter_id = maak_filter_aan( service, van=config.get('van'), onderwerp=config.get('onderwerp'), label_naam=config.get('label'), archiveren=config.get('archiveren', False), markeer_gelezen=config.get('markeer_gelezen', False) ) resultaten.append({'config': config, 'filter_id': filter_id}) return resultaten filter_configuraties = [ { 'van': '@klantdomeinnaam.nl', 'label': 'Klant A', 'markeer_gelezen': False }, { 'onderwerp': '[SPAM]', 'archiveren': True, 'markeer_gelezen': True }, { 'van': 'noreply@github.com', 'label': 'GitHub', 'archiveren': True } ] service = get_gmail_service() resultaten = importeer_filters_vanuit_config(service, filter_configuraties) ``` ## Filter verwijderen ```python def verwijder_filter(service, filter_id): service.users().settings().filters().delete( userId='me', id=filter_id ).execute() print(f'Filter verwijderd: {filter_id}') def verwijder_alle_filters(service): filters = haal_filters_op(service) for f in filters: verwijder_filter(service, f['id']) print(f'{len(filters)} filters verwijderd.') ``` :::warn title="Maak altijd eerst een back-up" Verwijder nooit alle filters zonder een back-up. Exporteer de bestaande filters eerst met `haal_filters_op()` en sla de output op als JSON. Zo kun je bij een fout de oorspronkelijke situatie herstellen. ::: ## Uitrollen naar een heel team Wil je filters niet voor je eigen account maar voor alle gebruikers in je Google Workspace-organisatie beheren, dan werk je met een serviceaccount en Domain-Wide Delegation. Het serviceaccount handelt dan namens elke gebruiker (impersonatie), zonder dat die gebruiker zelf hoeft in te loggen. :::tip title="Zo verloopt de uitrol veilig" Test je filterset eerst op een testaccount, draai daarna een dry-run die alleen logt wat er aangemaakt zou worden, en rol pas daarna uit naar de hele organisatie. Houd er rekening mee dat het maximum 1.000 filters per account is. ::: ## Veelgestelde vragen :::faq ### Kan ik filters beheren voor alle gebruikers in de organisatie? Ja. Via een serviceaccount met Domain-Wide Delegation kun je namens elke gebruiker filters beheren. Dit vereist beheerdersrechten en wordt geactiveerd in de Admin Console onder Beveiliging en API-besturingselementen. ### Ondersteunt de API ook AND/OR-logica? De Gmail API ondersteunt meerdere criteria per filter, die altijd als AND worden behandeld. OR-logica is niet mogelijk binnen één filter. Maak meerdere filters aan als je OR-gedrag wilt nabootsen. ### Kan ik filters importeren of exporteren als XML? Gmail heeft een eigen XML-export via Instellingen, dan Filters en geblokkeerde adressen, en dan Exporteren. Rechtstreeks XML importeren via de API kan niet. Je moet het XML-bestand eerst vertalen naar API-aanroepen. ### Welke scope heb ik nodig om filters te beheren? Lezen, aanmaken en verwijderen van filters gebruiken allemaal de scope `gmail.settings.basic`. Voor het aanmaken van labels heb je daarnaast `gmail.labels` nodig. ### Hoeveel filters kan ik maximaal aanmaken? Gmail ondersteunt maximaal 1.000 filters per account. Houd hier rekening mee bij bulk-uitrol, want bij overschrijding geeft de API een foutmelding. ### Worden filters direct toegepast op bestaande e-mails? Nee. Een filter dat je via de API aanmaakt geldt alleen voor nieuw inkomende berichten. Om bestaande berichten te verwerken moet je apart een zoekopdracht draaien en de gewenste acties op die berichten uitvoeren. :::