IMAP integration to read message body and toggle Hubspace outlet. I'm lost

So… I am at a complete loss at the moment. I have spent 2 days buried in all the IMAP, template, YAML, forum articles and documentation. I feel like the “only” ping pong ball at a Olympic table tennis tournament. I was trying to be respectful to all the forum users, by RTFM standards, but I’m just mush now.

I have a technical background, but I’m not a long-time user of HA or deep home automation stuff. I’ve just integrated some stuff like Hue lights, Ubiquiti stuff, Hubspace outlet, just to do simple stuff.

My goal is to use HA to turn on/off a hubspace outlet, which in turn controls the charging of my laptop, based on battery charge percentage.

My battery recently swelled, and HP warranty replaced it, as a “courtesy”. But they felt I didn’t have enough charge cycles (which was true… it stays plugged all the time). I didn’t want to manually charge/discharge, so I wrote a small shell script that uses upower to get the charge percentage. I then use monit, to monitor that output, and pass to M/monit, which sends emails. With this, I can cycle my hubspace outlet when mail hits the inbox. I have the IMAP integration setup (which just monitors a state change). That’s all well and good.

The email content I’m interested in contains the following important info:

‘status failed (24)’ - would turn on the Hubspace outlet and start charging.
‘status succeeded (95)’ - would turn off the Hubspace outlet and stop charging.

I finally, today, figured out the theory of setting up a “helper”, but I cannot figure out how to link that to my IMAP entity. I see them, I just don’t know what to do next… how to link or use the helper/template.

In my configuration.yaml I added a line

template: !include templates.yaml

I created a templates.yaml and I added this (which I hijacked out of a forum article)

trigger:
  - platform: event
    event_type: "imap_content"
    id: "haos_mail_eventid"
    event_data:
      sender: haos@<mydomain>.com
sensor:
  - name: haos_mail_sensor
    state: "{{ trigger.event.data['subject'] }}"
    attributes:
      Message: "{{ trigger.event.data['text'] }}"
      Server: "{{ trigger.event.data['server'] }}"
      Username: "{{ trigger.event.data['username'] }}"
      Search: "{{ trigger.event.data['search'] }}"
      Folder: "{{ trigger.event.data['folder'] }}"
      Sender: "{{ trigger.event.data['sender'] }}"
      Date: "{{ trigger.event.data['date'] }}"
      Subject: "{{ trigger.event.data['subject'] }}"
      

My automations,yaml has this for my basic toggle, which ia working presently

- id: '1730813515451'
  alias: Toggle outlet on alert email
  description: ''
  triggers:
  - trigger: state
    entity_id:
    - sensor.imap_haos_<mydomain>_com
  conditions: []
  actions:
  - type: toggle
    device_id: 68f140d806c70697b61283f621cd3531
    entity_id: eea9c9fb

Somewhere I tried this, though I can’t remember where… anyway, it contains the strings I’m trying to look for in the emails. It may need to be part of the above template, IDK.

template:
  - trigger:
      - platform: event
        event_type: "imap_content"
        id: "custom_event"
        event_data:
          sender: "notify@<mydomain>.com"
          initial: true
    sensor:
      - name: "OutletTriggerEmail"
        state: >-
          {% if 'status failed (24)' in trigger.event.data["body"] %}
            OutletOn
          {% elif 'status succeeded (95)' in trigger.event.data["body"] %}
            OutletOff
          {% endif %}

Anyway, thanks for listening, and if you pointers, Thank You in advanced!

Do you want a template sensor…? It’s not necessary since you can trigger the automation directly off the event.

As it stands, your last sensor config looks 95% of the way there with just a couple small issues, the main one being the use of “body” instead of “text” when retrieving the value from the trigger variable.

This is probably how I would do it currently. The examples you have seen likely do not use a condition block in the template sensor configuration… it is was only added recently. But it’s handy in this use case to act as an additional filter against rogue emails altering the sensor’s state.

template: #if this is in templates.yaml you don't need this line and it should throw an error
  - trigger:
      - platform: event
        event_type: "imap_content"
        event_data:
          sender: "notify@<mydomain>.com"
          initial: true
        variables:
          text: "{{ trigger.event.data['text'] }}"
    condition:
      - "{{ text is search('status\sfailed\s\(24\)|status\ssucceeded\s\(95\)') }}"
    binary_sensor:
      - name: "OutletTriggerEmail"
        state: "{{ text is search('status\sfailed\s\(24\)') }}"

The above configuration should produce an entity, binary_sensor.outlettriggeremail once you reload Template entities and/or Restart HA. Then you can use it in your automation:

triggers:
  - trigger: state
    entity_id: binary_sensor.outlettriggeremail
    to:
      - 'on'
      - 'off'
conditions: []
actions:
  - alias: This is a guess/approximation based on the available information...
    action: switch.turn_{{ trigger.to_state.state }}
    target:
      entity_id: switch.YOUR_HUBSPACE_OUTLET

Just FYI, the state of the sensor will be “unknown” until it receives it’s first IMAP content event.

FWIW, if you are comfortable writing your own shell scripts you might consider cutting out all the stuff in the middle and set up a Webhook trigger for your outlet automation instead.

I don’t require anything that was unneccessary, it was just where I ended up.

Actually, that was going to be the next item I worked on in M/monit. I figured that already being this deep into this method, it wouldn’t hurt to have worked it out.

I tried the code you provided but ran into some formatting issues, which I have not completely resolved yet. I put it in the Template Editor and received:

TemplateSyntaxError: unexpected char “'” at 508

I was able to resolve by changing the last line from this:

        state: "{{ text is search('status\sfailed\s\(24\) }}"

to this:

        state: "{{ text is search('status\sfailed\s\(24\)') }}" 

Now, I just receive Trigger is undefined

The second issue I have not resolved yet.

Screenshot from 2024-11-07 06-33-08

Here is what’s in that file

- trigger:
      - platform: event
        event_type: "imap_content"
        event_data:
          sender: "notify@<mydomain>.com"
          initial: true
        variables:
          text: "{{ trigger.event.data['text'] }}"
  condition:
      - "{{ text is search('status\sfailed\s\(24\)|status\ssucceeded\s\(95\)') }}"
  binary_sensor:
      - name: "OutletTriggerEmail"
        state: "{{ text is search('status\sfailed\s\(24\)') }}"

I carried it over to an added File Editor and it shows a similar error, but it looks the same as the previous line:

Thank you for the help thus far.

It seems like the YAML interpretter doesn’t like the \s, but the Template editor is fine with it…

Please double check that text was selected in the setup configuration flow for your IMAP integration, since it is off by default.

Since you don’t really require the sensor, just trigger the automation off the IMAP event. The following automation is working for me:

alias: Switch Outlet Email
description: ''
triggers:
  - trigger: event
    event_type: imap_content
    event_data:
      sender: "notify@<mydomain>.com"
    variables:
      text: '{{ trigger.event.data[''text''] }}'
conditions:
  - condition: template
    value_template: >
      {{ text is search("status failed \(24\)") or text is search("status succeeded \(95\)") }}
actions:
  - action: >-
      switch.turn_{{"on" if text is search("status failed \(24\)") else "off"}}
    metadata: {}
    data: {}
    target:
      entity_id: switch.laptop_power

So it took me about an hour to figure out where to put this… hehe… it’s not completinig, but at least the automation accepted it and tried to run it. I have to say the Developer Tools and the Traces are pretty handy, even for a non-developer. At least I have something to troubleshoot with.

On the code you gave me, when I place that in the Template Editor it complains with:

TemplateSyntaxError: expected token ',', got 'text'

So I remove the “text” from your line below, the error goes away.

 text: '{{ trigger.event.data[''''] }}'

If I try to add it back in, the Automation screen I get this:

*Message malformed: invalid template (TemplateSyntaxError: expected token ',', got 'text') for dictionary value @ data['actions'][0]['wait_template']*

So after getting the Automation created (below), I sent an email with the subject “status failed (24)”. On the Automations Traces screen I get this:

Triggered by the state of sensor.imap_haos_xancudo_com at November 7, 2024 at 1:38:53 PM

Wait for a template to evaluate to true

Stopped because an error was encountered at November 7, 2024 at 1:38:53 PM (runtime: 0.00 seconds)

In ‘template’ condition: UndefinedError: ‘dict object’ has no attribute ‘event’

id: '1730903833003'
alias: Toggle light with email
description: ''
triggers:
  - trigger: state
    entity_id:
      - sensor.imap_haos_<mydomain>_com
conditions: []
actions:
  - wait_template: |-
      alias: Switch Outlet Email
      description: ''
      triggers:
        - trigger: event
          event_type: imap_content
          event_data:
            sender: "notify@<mydomain>.com"
          variables:
            text: '{{ trigger.event.data[''''] }}'
      conditions:
        - condition: template
          value_template: |
            {{ text is search("status failed \(24\)") or text is search("status succeeded \(95\)") }}'
      actions:
        - action: switch.turn_{{"on" if text is search("status failed \(24\)") else "off"}}
          metadata: {}
          data: {}
          target:
            entity_id: switch.laptop_power
    continue_on_timeout: true
mode: single

All in all, progress!!

The Template editor only understands Jinja templates, it can’t parse YAML and it has no access to the trigger variable, so you can’t drop configuration directly into it and get

Regarding my previous post… it’s a complete automation, you do not need the previously discussed State trigger because the automation is using the imap_content event itself as its trigger. Remove the State trigger and make sure to correct the value for sender.

For reference, this is what it looks like in the Automation editor:

I have left the trigger collapsed, as it contains personal information. For clarity, as shown in the configuration shared in my previous posts, it is an Event trigger. In the Automation editor Event triggers are listed as Manual Event.

If you need one, there is a slightly dated, but still informative video primer on translating between YAML and UI editor available on the ResinChem Tech Youtube channel .

I appreciate what all you posted. It’s actually helped me a lot, and I have it running. Its executing but just hasn’t found a “pass” condition yet, so I’m going to work on that, and see what I can find out.

Again, I appreciate your time!!

So just an update that I got this working, to a point. The biggest WIN was due to your screenshot. I could not find “When imap_content event is fired” in my visual editor.

The biggest hurdle in this, I think, is just understanding how many different places code can be injected. Once I found the YAML Editor that displayed the entire Automation, I pasted your entire code in, and then I went back to my Visual editor and saw how these lines where segmented, and how it compared to your screebshot. I still have not found where to select that imap event part. But I at least know how to create it in YAML editor now.

Thanks again!

This is working now, so I wanted to post the final code

alias: Toggle laptop power with M/Monit email
description: Toggle Hubspace outlet on at 24% battery remaining, and toggle back off at 96% battery remaining with alert email
triggers:
  - trigger: event
    event_type: imap_content
    event_data:
      subject: Status failed batt_level
    variables:
      text: "{{ trigger.event.data['text'] }}"
conditions:
  - condition: template
    value_template: >-
      {{ text is search("status failed \(24\)") or text is search("status failed
      \(96\)") }}
actions:
  - action: switch.turn_{{"on" if text is search("status failed \(24\)") else "off"}}
    metadata: {}
    data: {}
    target:
      entity_id: switch.laptop_power