Sendmail - Send email and text notifications, (notification device) no local server needed

I'd read the thread, but it works perfectly. :slight_smile:

Something about HPM. Perhaps one day.

If you can't use Sendmail, then as posted just above, @ritchierich's integration supports notifications via Gmail. Also works very well.

1 Like

Thanks. I'll try again, but I thought I tried all possible settings/ports/options. I probably got something wrong for my particular setup..

This is the log when it expires after the three retries.

Is there a way to change the Subject in the message that you set in the device so that I could use the 1 SendMail device for many notices?

I could not find a way in webCore or RM

The system notification call has no option for that. The only thing i can think of is a custom attribute you could set in a rule before sending the notification. But this would only work in std rule machine as other methods would not be able to do it. Not sure of the benefits.

In the other app that lets you send email (via Gmail), you can set a per-message Subject: by prefixing the message with "Subject:" and ending the subject with a comma.

E.g., "Subject: this is the subject,This is the body"

(@kahn-hubitat if you implement something, I'd suggest you make it compatible with that)

1 Like

Correct. @kahn-hubitat I have an if statement in my code that looks for this condition:

if (message.startsWith("Subject:") && message.indexOf(",") > -1) {
  def messageSplit = message.split(",")
  subject = messageSplit[0].replace("Subject:", "")
  message = messageSplit[1].trim()
}

Maybe you can do something similar.

4 Likes

Good idea i will look at implementing that.

3 Likes

Just in case you want to see the entire code its in the sendMessage function starting on line 1147:

Basically the subject gets passed into this function which defaults to the setting value on the child notification device and this code will overwrite it if the subject keyword is included in the message.

2 Likes

I am going to generalize that concept. But with a specific order caveat.

To: first
Cc: 2nd
Subject: third

If you put them in that order i think i could implement the capability to change all of them.

4 Likes

new version 4.9

  • v 4.9 1/2023
  • new changes to be able to modify/replace the From, to , subject or add a cc header
  • the syntax is rh-Header: value,
  • for instance to replace the subject form the hardcoded subject in your configuration would be: rh-Subject: New Subject, Remainder of the message
  • There must be a comma after each replacment header directive.
  • same for to rh-To:, From is rh-From,
  • to add a CC header, it is rh-CC: email@email.com etc.
  • Notes: if you had a list of multiple to addresses in the configuration panel only one can be in the new replacment header so that would override the entire list.
  • other notes, order is important if you want to replace all headers (hence the rh-headername) you need to put them in this order:
  • rh-From, rh-T0, rh-Subject, rh-CC .
  • You dont need them all, but if any are there they must be in that order as that is the order they are processed.
  • Otherwise they will be left in as part of your actual message.

let me know if you find any issues.

3 Likes

here is the bulk of the code change if you are interested.

Summary

// note order is important here from, to, subject,cc
if (state.debug) log.debug "before check for header replacment, subject = $emlSubject, body = $emlBody, from = $From, To = $To"

      if (emlBody.startsWith("rh-From:") && emlBody.indexOf(",") > -1)
           {
               def io = emlBody.indexOf(",")
               def len = emlBody.length()                             
               if (state.debug) log.debug "found replace header for From! index = $io, len = $len" 
               def newFrom = emlBody.substring(0,io)
               def messageSplit = emlBody.substring(io+1,len)           
               From = newFrom.replace("rh-From: ", "").replace("rh-From:", "")
               emlBody = messageSplit.trim()
            }  
           
         if (emlBody.startsWith("rh-To:") && emlBody.indexOf(",") > -1)
           {
               def io = emlBody.indexOf(",")
               def len = emlBody.length()                                   
               if (state.debug) log.debug "found replace header for To! index = $io, len = $len" 
               def newTo = emlBody.substring(0,io)
               def messageSplit = emlBody.substring(io+1,len)
               To = newTo.replace("rh-To: ", "").replace("rh-To:", "")
               emlBody = messageSplit.trim()
               toReplaced = true
            } 
           
       if (emlBody.startsWith("rh-Subject:") && emlBody.indexOf(",") > -1)
           {
               def io = emlBody.indexOf(",")
               def len = emlBody.length()                  
               if (state.debug) log.debug "found replace header for Subject!"                  
               def newSubject = emlBody.substring(0,io)
               def messageSplit = emlBody.substring(io+1,len)
               emlSubject = newSubject.replace("rh-Subject: ", "").replace("rh-Subject:", "")
               emlBody = messageSplit.trim()
            }    
         
        if (emlBody.startsWith("rh-CC:") && emlBody.indexOf(",") > -1)
           {
               def io = emlBody.indexOf(",")
               def len = emlBody.length() 
               if (state.debug) log.debug "found replace header for CC!" 
               def newCC = emlBody.substring(0,io)
               def messageSplit = emlBody.substring(io+1,len)
               cc = newCC.replace("rh-CC: ", "")replace("rh-CC:", "")
               emlBody = messageSplit.trim()
               ccFound = true 
            }

note: according to groovy specification trim() is supposed to trim white space from both the beginning and end of a string, but in hubitat it only seems to trim the end. Thus I had to work around it and that is why you see the double replace in the code.

1 Like

Why the prefix? :slightly_frowning_face:

for replace header rh so not do confuse becuase you can have From: or to: easily as the start of a message.

1 Like

I really wouldn't think that would almost ever happen. I really wish you were compatible with @ritchierich's format.

But thanks for adding the feature!

2 Likes

@kahn-hubitat happy to work with you to make something consistent. I considered including other attributes such as To but decided against it for my initial release. One thought is to require an “object/map” be passed via message string and our code could look for message starting with { and ending with }. For example:
{Subject:Email Subject, To:user@example.com, Message: This is a test}

Then code would parse the string to JSON object and gather the values and substitute from default settings if entered. This wouldn’t require prefixes and keys could be entered in any order but it will require a Message key.

2 Likes

Interesting but no need to change the message as i want to still allow that at the end so that anything in place works without changes.

I was also thinking of leaving what have done
And just adding the subject: header and then it would work with what you have and that would by far be simplest.

I also could easily alleviate the order dependency with what i have by checking at top with a big compound if and wrapping the code in a loop but figured it wasn't necessary as the functionality is already there.

But if you implement something with {header: value, header: value }, Message

I would use your code

The cc case was a slightly more complicated for me as it adds a new header not just swap one.

Also what would happen with multiple subjects or multiple froms as the syntax would allow it.

Ok for.now i will just two ver 4.91 and add the subject: header and then see what shakes out.

Rambling done.

3 Likes

2 sec. change

new version 4.91

  • 4.91 added option for the subject header to be rh-Subject: or just Subject: to be consistent with ritchierich code base so you can
  • have one notification send through both implementations.
2 Likes

@kahn-hubitat I just tested this in my app and it works. Message sent would be:
{Subject:Email Subject , Message:Email body, To:name@example.com}

Only difference is my Gmail notification won't accept a From since that is defaulted by the API.

I tried to convert the string to a JSON object but ran into issues since it would require quotes around the key and value so came up with a different method. Hopefully this works in your app:

if (message.startsWith("{") && message.endsWith("}")) {
	message = message.replace("{", "")
	message = message.replace("}", "")
	def messageSplit = message.split(",")
	def messageObject = [:]
	for (int i = 0; i < messageSplit.size(); i++) {
		def messagePart = messageSplit[i]
		def messagePartSplit = messagePart.split(":")
		if (messagePartSplit.size() == 2) {
			messageObject[messagePartSplit[0]] = messagePartSplit[1].trim()
		}
	}

	toEmail = (messageObject.containsKey("To")) ? messageObject.To : toEmail
	subject = (messageObject.containsKey("Subject")) ? messageObject.Subject : subject
	message = (messageObject.containsKey("Message")) ? messageObject.Message : message
	fromEmail = (messageObject.containsKey("From")) ? messageObject.From : fromEmail
}
1 Like

That's not gonna work for me as i said it would break all existing stuff to have the closing bracket at the end and the message inside.

Also would break messages with commas in them which is why i.didnt use.split. i could modify it to isolate the begin and end bracket leaving the message after it and then call your code.