title: Cloud function with pubsub trigger executed endlessly when calling gmail API messages.send()
body: <p>We are using the Atlassian Status Page with email automation, which means that it displays an alert on screen whenever it receives an email with subject 'DOWN' and deletes the same alert when it receives an email with subject 'UP'.</p>
  <p>I activated the Gmail Pub/Sub (<a href="https://developers.google.com/gmail/api/guides/push" rel="nofollow noreferrer">https://developers.google.com/gmail/api/guides/push</a>) push notifications, which watches the gmail inbox for changes and sends a push notification to a pub/sub topic when a change actually happens.</p>
  <p>Then I created a cloud function which is triggered by pub/sub notifications. This cloud function should:</p>
  <ol>
  <li>Read the latest unread email</li>
  <li>If this email is an alert sent by our 3rd party provider, send a new email to the Status Page with subject 'DOWN' or 'UP' accordingly.</li>
  </ol>
  <p>This is the code:</p>
  <pre><code>def access_oauth2_json():
    ### Code
    return creds_dict
  
  
  def create_message(subject):
    ### Code
    return {'raw': b64_string}
  
  
  def send_message(service, message, user_id = 'me'):
    try:
      response = service.users().messages().send(userId=user_id, body=message).execute()
      return response
    except HttpError as error:
      logging.error('An error occurred:', error)
  
  
  
  def update_status_page(arg1,arg2):
  
    ### Initialise creds
  
    try:
      service = build('gmail', 'v1', credentials=creds)
      request = {
        'labelIds': ['INBOX'],
        'topicName': 'pubsub_topic_id'
      }
      service.users().watch(userId='me', body = request).execute()
  
      last_message_info = service.users().messages().list(userId='me', labelIds=['UNREAD'], q = 'in:inbox is:unread', maxResults=1).execute().get('messages', [])
  
      last_message = service.users().messages().get(userId='me', id=last_message_info[0]['id']).execute()
  
      header = last_message['payload']['headers']
      sub = &quot;&quot;
      for x in header:
        if x['name'] == 'Subject':
          sub = x['value'] #subject
          logging.info(sub)
  
      if 'special_alert_string' in sub:
        message = create_message(subject = 'DOWN')
        response = send_message(service, message)
      elif 'other_special_alert_string' in sub:
        message = create_message(subject = 'UP')
        response = send_message(service, message)
  
    except HttpError as error:
      logging.info(f'An error occurred: {error}')
  
    return 200
  </code></pre>
  <p>What happens is that:</p>
  <ol>
  <li>When the function is triggered by an email which is <strong>not</strong> a 3rd party alert, the if/elif blocks are not executed, and the cloud function is executed 2 or 3 times (instead of 1, but that's fine for me, so not really a problem)</li>
  </ol>
  <p><a href="https://i.stack.imgur.com/tyy5z.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/tyy5z.png" alt="Highlighted the execution IDs of the functions" /></a></p>
  <p>2 - <strong>Problem</strong> - When the function is triggered by an email which <strong>is</strong> a 3rd part alert, the if/elif blocks are executed (one of the 2) and the function is executed endlessly! It only stops because it reaches the maximum API requests per interval of time.</p>
  <p><a href="https://i.stack.imgur.com/wPeta.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/wPeta.png" alt="enter image description here" /></a></p>
  <p>What I have tried:</p>
  <ol>
  <li>To remove the watch() line, without success</li>
  <li>Commenting out the service.users().messages().send() line falls back into case 1, so my guess is that this instruction is triggering a push notification to the pub/sub topic and generates the infinite loop. The issue could maybe solved with another watch() labelId, but I haven't figured out which one.</li>
  </ol>
  <p>I hope this is clear, thank you for your help!</p>