Using the IMAP integration to create a custom event from an email - HELP PLEASE!

Hi

I want to use the Home Assistant IMAP integration to create a custom event to trigger an automation when my Gmail receives certain emails.

I’ve been trying to follow the steps at IMAP - Home Assistant but am struggling a bit.

Here’s the background:

  • My home alarm does not have an official Home Assistant integration.
  • I want my Home Assistant to monitor the status of my home alarm (which is either Fully Armed, Part Armed or Disarmed).
  • My home alarm can send emails upon a change in state to Fully Armed / Part Armed / Disarmed.
  • I have these email notifications sent to my Gmail account and have setup three basic IMAP integrations, one for each of the IMAP search functions to identify the status of the home alarm from the body of the email, but this integration just reads the number of emails which meet the search criteria which is not helpful.
  • My profile is set to advanced mode.

Questions:

  • I want to create a Gmail rule which files these home alarm email notifications in a separate Gmail folder so it doesn’t clog up my inbox. However, I cannot seem to configure the IMAP integration search function to search anywhere other than the INBOX folder. If I write a different folder - e.g. “[Gmail]/Alarm” - I get an error to say the selected folder is invalid). What is the correct way to identify a folder for the search function?

  • How can I create a custom event from these emails? I’ve seen the suggested code below and tried to follow the IMAP integration steps, but I am not sure where to put this code - is it in the configuration.yaml (which I have tried and hasn’t seemed to work)? And how would I tailor this code once it is in there? How would I create a dashboard item that shows the status of the alarm (green/DISARMED, amber/PART ARMED and red/FULLY ARMED) from what emails I have received?

Many thanks in advance

1 Like

Since you’re using a separate instance of the integration anyway, just set the folder there. There probably isn’t any benefit in having “one for each of the IMAP search functions to identify the status of the home alarm from the body of the email” because you will just have to recombine and sort them to determine the current state.

Receiving an email that matches the integration configuration and search criteria already creates an event. You can add custom data to that event by using the “Template to create custom event data” box shown above, but that is probably unnecessary.

The content sensor is a Trigger-based Template sensor. You will likely need to put it in configuration.yaml or templates.yaml, depending on whether/how the template integration is included in your configuration. You will have to share that information for us to be able to give you guidance.

It is hard to give a definitive answer without seeing how you have configured your integration(s), but from what you have said, it will be something like:

  - trigger:
    - platform: event
      event_type: "imap_content"
      event_data:
        username: [email protected]
        folder: Alarm
    sensor:
    - name: Alarm Status
      state: |-
        {% set body = trigger.event.data['text'] %}
        {% if body is search('Fully Armed') %} Fully Armed
        {% elif body is search('Part Armed') %} Part Armed
        {% elif body is search('Disarmed') %} Disarmed
        {% else %} Error {% endif %}

Note: You could also move this template (with some modifications) into the configuration as mentioned above. This is just a difference of personal preference, you would still need a template sensor to have something to reference for your dashboard card. As with many things in HA, there are multiple ways to accomplish similar results.

There are way too many ways to do dashboard cards to answer this unless you narrow the options first. Since you want to control the state colors, you will likely want to use a card that allows templating such as Mushroom Cards or Custom Button Card.

The IMAP integration supports the basic set of IMAP search commands as well as Gmail’s search command extensions.

Here’s the example found in the IMAP integration’s documentation:

X-GM-RAW "in: inbox older_than:7d"

Based on that example, and the information in the GMail extensions document, we can create a search to look for messages in “yourfolder” containing the word “armed” or “disarmed”.

X-GM-RAW "in: yourfolder armed OR in: yourfolder disarmed"

Be advised that I have never used the IMAP integration and what I have presented here is based upon about 15 minutes of reading the available documentation. In contrast, Didgeridrew is an experienced IMAP user so follow his advice.

Gmail accounts are free. Set up another for the alarm. You can get it to forward all emails to your existing account if you want it all in one place.

thank you @nickrout, @123 and @Didgeridrew very much for your replies, really appreciate it.

@123 - replacing “inbox” in "X-GM-RAW "in: inbox older_than:7d" with my folder name but didn’t seem to work properly? I will try @Didgeridrew’s suggestion in the trigger coding

@nickrout - I already have a few Gmail accounts and I am trying to manage the proliferation of these accounts, so want to avoid creating yet another Gmail account. I just want to have a way for the IMAP integration to search a folder other than the INBOX.

@Didgeridrew - thank you once again for your detailed response. I put the code in the templates.yaml as below (slight tweaking of your code)

- trigger:
    - platform: event
      event_type: "imap_content"
      event_data:
        username: !secret gmail_username
        folder: alarm
  sensor:
    - name: Alarm_Status
      state: |-
        {% set body = trigger.event.data['body'] %}
        {% if body is search('Arm' %} Fully Armed ###I NEED TO EXCLUDE 'part' FROM SEARCH###
        {% elif body is search('Part Arm') %} Part Armed
        {% elif body is search('Disarm') %} Disarm
        {% else %} Error {% endif %}

Does this look correct?

A few questions/issues:

  1. The email I receive when alarm is Fully Armed does not actually use “Fully” in the body, it just doesn’t have Disarm. How would I write this to exclude if Disarm is in the search?

  2. I get the below error in homeassistant.config when I restart:

Invalid config for [template]: invalid template (TemplateSyntaxError: unexpected ‘}’, expected ‘)’) for dictionary value @ data[‘sensor’][0][‘state’]. Got “{% set body = trigger.event.data[‘body’] %}\n{% if body is search(‘Arm’ %} Fully Armed\n{% elif body is search(‘Part Arm’) %} Part Armed\n{% elif body is search(‘Disarm’) %} Disarm\n{% else %} Error {% endif %}”. (See /config/template.yaml, line 0).

  1. I cannot fit the entity “sensor.alarm_status” in the States section of the Developer Tools - shouldn’t it be there? How do I reference this sensor?

  2. I’ll look into Mushroom cards.

thanks again

I’m not surprised it failed to work because I never suggested you should do that. Review what I wrote, again.

Apologies @123 - I actually got it to work by writing the folder name in lower case in the Configure option of the integration and the integration is counting the emails in that folder perfectly.

Still not sure how to make this so that Home Assistant IMAP integration is able to find the most recent email in that folder and then have a sensor pick up the alarm status from that email content?

Thanks

You’re missing a closing parenthesis ) after search('Arm' in the second line of the template.

If I understand correctly, you should be able to add an “and” clause:

{% if body is search('Arm') and not body is search('Part') %} Fully Armed

The sensor won’t appear until the configuration is correct, i.e. the error is fixed.

@Didgeridrew - brilliant, thanks, this is now showing the sensor, so big step! The issue is the status is showing as Unknown, so the sensor isn’t quite working correctly. Also, how would it look to the most recent email as that would be the one which has the current state? Thanks

It will be “unknown” until the trigger is fired. You can force it by reloading the IMAP integration from the integration’s page.

The IMAP integration itself doesn’t do that, it just posts the event to the event bus when new emails meeting the search criteria are pushed from the server.

Thanks - I reloaded and now the sensor is showing ‘error’…

Also, how would this work given I only want to take the most recent email in the alarm folder (there will be lots of emails that come up in the search for Arm / Part Arm / Disarm - I want the search to only look at the newest email in the alarm folder and get the state from that email.

If you’re getting “error” then the most recent email in the folder doesn’t match any of the search criteria.
Just FYI the search criteria are case sensitive by default.

Try Arming or Disarming the system to see if it changes.

If you need a maximally selective sensor, there are a couple things you can do:

  1. Add stricter criteria to the template. For example you can restrict updating the state if the date of the event data is more than X minutes old.
  2. Set up a script in Gmail/Appscripts to delete all but the newest email.
Google AppScript to trash old messages
function removeAllButMostRecent() {

  var tagList = ["Alarm"];

  for ( var j = 0; j < tagList.length; j++ ) {

    var label = GmailApp.getUserLabelByName( tagList[j] );

    if ( label != null ) {
      var threads = label.getThreads();

      for ( var i = 1; i < threads.length; i++ ) { // skip most recent one
          threads[i].moveToTrash();
      } // for
    } // if
  } // for
} // function

thanks - i’ve checked and there are definitely emails - including the most recent email in the folder - which matches one of the search criteria, including on a case sensitive basis. Weird why this isn’t working.

This works independently of the basic IMAP integration? I say that as I have three IMAP integrations, one which shows the number of Fully Armed, one which shows the number of Disarmed and another that shows the number of Part Armed. They seem to be picking up the number of emails fine, although the search for those is captured in the configuration of the integration entity.

No, the IMAP integration is responsible for establishing the connection to the server, setting up the search criteria the server bases it’s push content off of, receiving the push from the server, and posting the event to the event bus.

Does each instance of the integration have a unique Search? It might be better to restructure the content sensor to use multiple triggers if that is the case.

Yes they do. They all search the same folder (alarm) and have the same max message size (2048) but they have three different IMAP searches as follows:

  • UnDeleted X-GM-RAW “disarm”
  • UnDeleted X-GM-RAW “arm -disarm -part”
  • UnDeleted X-GM-RAW “arm part -disarm”

The basic IMAP integration is working fine, but I think because I have three unique searches in these integrations, that’s then interfering with the template/trigger/event coding you suggested. How would I restructure the content sensor to use multiple triggers if that’s the best solution?
Thanks

- trigger:
    - platform: event
      event_type: "imap_content"
      id: Disarm
      event_data:
        username: !secret gmail_username
        folder: alarm
        search: UnDeleted X-GM-RAW "disarm"
    - platform: event
      event_type: "imap_content"
      id: Fully Armed
      event_data:
        username: !secret gmail_username
        folder: alarm
        search: UnDeleted X-GM-RAW "arm -disarm -part"
    - platform: event
      id: Part Armed
      event_type: "imap_content"
      event_data:
        username: !secret gmail_username
        folder: alarm
        search: UnDeleted X-GM-RAW "arm part -disarm"
  sensor:
    - name: Alarm_Status
      state: |-
        {% set current = this.state | default('Error') %}
        {{ trigger.id if (trigger.event.data['date'] >= now() - timedelta(minutes=1)) else current }}

thanks - yikes the Alarm_Status entity is still showing an error after changing the template yaml to that…i’ve restarted YAML configurations and IMAP integrations multiple times and still no success. there are definitely emails in the alarm folder that match the search criteria as the individual IMAP sensor entities are counting these emails correctly.

1 Like

Let’s try simplifying the trigger criteria… get rid of the the username and folder lines for each trigger. Then restart HA. Once everything is up, arm or disarm the alarm so new messages are sent.

As your suggestion, I changed template.yaml so it reads as below but did not change the configuration of the IMAP integration entities (so they still have alarm in the folder even if the trigger now has it removed). I then sent an email to this gmail inbox with both “Disarm” and “disarm” in the email body. The Alarm_Status sensor is showing an error when the new message is inbox and also when I added the “alarm” label on this email so it was in both the inbox and alarm folders (but the IMAP integration is still reading the correct number of emails based on this search)…

- trigger:
    - platform: event
      event_type: "imap_content"
      id: Disarm
      event_data:
        search: UnDeleted X-GM-RAW “disarm”
    - platform: event
      event_type: "imap_content"
      id: Fully Armed
      event_data:
        search: UnDeleted X-GM-RAW “arm -disarm -part”
    - platform: event
      id: Part Armed
      event_type: "imap_content"
      event_data:
        search: UnDeleted X-GM-RAW “arm part -disarm”
  sensor:
    - name: Alarm_Status
      state: |-
        {% set current = this.state | default('Error') %}
        {{ trigger.id if (trigger.event.data['date'] >= now() - timedelta(minutes=1)) else current }}

:man_facepalming:

I think it’s the stupid “pretty” quotes in the search:… I’ve corrected it my post above.