Help with imap template please

I get a daily email from my electric company that shows the previous days usage and estimated cost.

I want to set up an imap sensor to track the email, but I want it to use the values in the email for sensor information so I can see it on a graph in the front end.
How would I go about that?
My current email sensor has a template that says “IF the body of email says xyz, state should be zyx” but I don’t need that.
I need a value template that says “Body value is xyz, state should also be xyz”

Thanks!

It would be helpful if you could post your current sensor configuration. Of course redact any sensitive info (like username & password.)

What information do you want to pull out? Just one piece of data, or more than one?

My current one is for something else, but is like this.

- platform: imap_email_content
  server: imap.gmail.com
  port: 993
  username: [email protected]
  password: xxx
  name: bus
  folder: inbox
  senders:
    - xx
    - kaxxx
  value_template: >-
      {% if "entered JACOB ---'s bus stop radius" in body %}
        Jacobs bus is arriving soon
      {% elif "entered JONAS ---'s bus stop radius" in body %}
        Jonas' bus is arriving soon
      {% endif %}

That gives me a sensor with 2 possible states - which is then output through Alexa as “Jacobs bus is arriving soon” or Jonas’ bus is arriving soon"

For this one - what I am trying to figure out is how to make a sensor that has 3 attributes - power consumed the day before, let’s call it Previous Day KWH, Previous Days Cost and Monthly Cost.
So I need to find out how to make the sensor update daily (which happens with the new email) and have those attributes equal the info from the email.

I hope I make sense, haha.
So something like
{% if 'Yesterday’s Energy Use: XX kWh" ’ in body %}
xx kWh
{% if 'Yesterday’s estimated energy cost:: $yy" ’ in body %}
$yy

xx and yy will change daily so I need to find a way to extract those values

My current sensor for this is just a simple

- platform: imap_email_content
  server: imap.gmail.com
  port: 993
  username: [email protected]
  password: xxx
  name: energy
  folder: inbox
  senders:
    - [email protected]

If I use {{ state_attr(‘sensor.energy’, ‘body’) }} I do get the body but can’t figure out how to pull the info that I’ve put the red box around.

I think what I am looking is something similar to this with my sensor (I’m okay with making multiple sensors, one per input I want)
but I need it to get
“Yesterday’s Energy Use:” PLUS the next 6 text characters since that’s the actual value (in this screenshot; the 76 kWh)

value_template: >-
      {% if 'Yesterday's Energy Use:" ' in body %}
        xx kWh

Your bus sensor’s value_template should have an {% else %}. Otherwise if neither of the if’s evaluate to true it will cause an error. You could either change the elif to else, if you know the e-mail will always have one or the other, or add an else clause with something like unknown.

So I don’t use the imap_email_content sensor, and per the docs it certainly wasn’t clear that it had attributes for body, etc. But that’s a good thing! :slightly_smiling_face: I think what I’d do is to leave that sensor as is. Then I’d create three template sensors that pull out the pieces you’re looking for. For example:

sensor:
- platform: template
  sensors:
    previous_day_energy_use:
      friendly_name: Previous Day Energy Use
      unit_of_measurement: kWh
      value_template: >
        {{ state_attr('sensor.energy', 'body')
           |regex_findall_index("\*Yesterday's Energy Use:\* ([0-9]+) kWh") }}

You could create similar template sensors for the other two values, or add them as attributes to the above. Let me know if you need more help or if you have any questions about what I suggested above.

Strange, for the bus one, it works though haha.

I will try out your suggestion and report back. Thank you!

Sure, it works, but it’s not written very robustly. As I said, if the e-mail body did not contain either of those strings it would result in an error because the value_template would evaluate to nothing. And if you know it will always contain at least one of the two strings, then there’s no need for the elif statement, because if the if evaluated to false, then the elif would always evaluate to true. So one of the following would be better than what you currently have:

  value_template: >-
      {% if "entered JACOB ---'s bus stop radius" in body %}
        Jacobs bus is arriving soon
      {% elif "entered JONAS ---'s bus stop radius" in body %}
        Jonas' bus is arriving soon
      {% else %}
        Unexpected e-mail content
      {% endif %}

or

  value_template: >-
      {% if "entered JACOB ---'s bus stop radius" in body %}
        Jacobs bus is arriving soon
      {% else %}
        Jonas' bus is arriving soon
      {% endif %}

Basically, in most situations an if should always have an else.

Thank you! I changed it to one of your suggestions.

The example you gave for the kWh works great! I am trying to modify it for the other 2 but I am struggling a little with the regex. I’ve found some guides online but nothing I attempt works well.
How would I use it to get the value for $8 instead of the kWh?
:* ([0-9]+) kWh") }}

In my very limited understanding so far, I think its because regex reads “$” as the end of a string so I’,m not using it correctly. Once I get going, I can generally fumble my way through something but I’m lost here.

Thank you again so much for your help!

Just a quick explanation of the kWh regex:

"\*Yesterday's Energy Use:\* ([0-9]+) kWh"

First, the * character has special meaning (i.e., match zero or more of the previous character), so it has to be “escaped” (i.e., preceded with the “escape character”, which is \ by default) to match a literal * character. Next the [0-9]+ part means match one or more (+) characters that are 0 through 9 ([0-9]). Lastly the parentheses around [0-9]+ means create a group of these characters. By default the regex will output only the characters from this group.

To match the cost I’d suggest:

"\*Yesterday's estimated energy cost:\* \$([0-9.]+)"

That will extract any string of digits and/or period character after the dollar sign.

EDIT: Added an escape character before the $.

Oops, you’re right. I’ll edit my previous reply accordingly.

You are the real MVP. Thank you! They’re both working and I was able to add the 3rd I wanted. It’s hard for me to ask for help because I am someone who tends to get tunnel vision until I figure it out so you saved me days. Thank you!

1 Like
- platform: imap_email_content
  server: imap.gmail.com
  port: 993
  username: !secret gmail_user
  password: !secret gmail_password
  name: Lawn Care
  folder: inbox
  senders:
    - [email protected] 
  value_template: '{{ state_attr("sensor.lawn_care", "subject") }}'

I realize this is an older thread but I see the people here are very knowledgeable in getting this setup. I am trying to read the words Upcoming Visit from the subject of an email from the lawn guy soI can open the gate when hes on his way. The way I am setting it up the state always says unknown. Can someone lead me in the right direction please and thank you!

As I stated before, I don’t use this integration, so I’m only going by the documentation. But based on what you say you want to do, I think you should just leave value_template out of the sensor configuration. Then the state of the sensor will be the subject of the most recently received e-mail. Then you can simply do something like this in your automation’s trigger:

- trigger:
    platform: template
    value_template: >
      {{ 'Upcoming Visit' in states('sensor.lawn_care') }}

Now, it’s possible you don’t receive many e-mails from that sender, and therefore you might receive two e-mails in a row (although possibly long apart in time) that both have ‘Upcoming Visit’ in the subject. If this were to happen, then it wouldn’t trigger the second time. (After the first time it triggers, a template trigger must evaluate to False and then back to True to trigger again.) So a more fulproof way would be:

- trigger:
    platform: state
    entity_id: sensor.lawn_care
  condition:
    condition: template
    value_template: >
      {{ 'Upcoming Visit' in trigger.to_state.state }}

To be clear are you saying If I set up the sensor like this it will read the subject of the incoming emails

- platform: imap_email_content
  server: imap.gmail.com
  port: 993
  username: !secret gmail_user
  password: !secret gmail_password
  name: Lawn Care
  folder: inbox
  senders:
    - [email protected]

See the documentation where it says:

If a template is not supplied the message subject will be used for the sensor value.

Also, the sender e-mail address – [email protected] – doesn’t seem correct. Is that a typo, or did you just redact it?

The email is redacted👍🏻 the sensor reads unknown at all times that’s why I am verifying if setting it up as written above is all it needs.

Well I just gave it a try. Here is my config:

sensor:
- platform: imap_email_content
  server: imap.gmail.com
  username: !secret notify_snd_email_username
  password: !secret notify_snd_email_password
  senders:
  - !secret notify_phil_email_address

The username/password is the account I use for sending notifications, and the sender is the e-mail address I usually send those notifications to. (Hence the secret names.) In this case it’s basically reversed – i.e., I’m sending from the account I usually receive e-mail notifications from HA on, and I’m receiving on the account I usually use to send e-mail notifications from HA on.

Anyway, at first the state was unknown. Then I sent an e-mail, and on the next query the state changed to the subject line of the e-mail. (Note that this sensor queries the server every 30 seconds.)

1 Like

That’s great. So the reason it’s reading unknown is because he hasn’t sent me an email yet.

So I’m about halfway where I want to be with my setup. Here’s what I got.

This is a sample of the email I receive from my electric company:

The OG&E SmartHours price for electricity will be at the High rate of 22
cents per kilowatt hour between 02:00 PM - 07:00 PM on Monday,
06/08/2020. Would you rather receive this information via phone call or
text? You can adjust your settings at oge.com/alerts.

This is my config.yaml:

sensor:
  - platform: imap_email_content
    server: mail.server
    port: 993
    username: [email protected]
    password: 12345678
    name: smarthours_email
    senders:
      - [email protected]
    value_template: body

  - platform: template
    sensors:
      smarthours_price:
        value_template: >
         {{ state_attr('sensor.smarthours_email','body')
           |regex_findall_index("(\d+) cents") }}

The first half works perfectly. I get the email, and I’m able to read the body within sensor.smarthours_email.

The second half is what I’m struggling with. I’m always getting an “unknown” state with both the expression listed in my code as well as what’s suggested in the documentation. If I change it to

{{ state_attr('sensor.smarthours_email','body')
           |regex_findall_index("cents per kilowatt hour") }}

it works as expected(as best you can expect a string of useless data to work :laughing:), so I know everything is working except the regular expression. I also tried

("\*rate of \*([0-9]+)") 

with no luck.

I think the problem is there is an end-of-line between “22” and “cents”, and your regular expression does not account for that (it’s expecting a single space character.) Try this:

  - platform: template
    sensors:
      smarthours_price:
        value_template: >
         {{ state_attr('sensor.smarthours_email','body')
           |regex_findall_index("(\d+)\s+cents") }}

Also, I don’t think the “first half works perfectly.” I suspect the state of sensor.smarthours_email is always exactly the word “body”, right? Of course, if that’s what you want, then I guess it does work perfectly. :wink:

1 Like

Hi Phil,
Thanks for the reply. That worked! I was up till 3am trying to figure that silly thing out.

HA, yaml, and all this scripting/programming is new to me as of about 2 weeks ago.

To answer your suspicions, yes, the state is always body for sensor.smarthours_email. Just in my very limited understanding of the documentation, I thought that sensor has to exists so the other sensor can pull the price info from it. What would you suggest doing? Any suggestions to help me streamline the process would be appreciated.