Send an email from a controller


#1

This got covered over in a post in the ‘Applications’ forum, but I felt it worth putting in here as well.

While the scratchpad is the main way to send an email from a PAC Controller, its not the only way…
There is another;

Use a chart to talk to your email server.
This is pretty powerful as we are all very used to working in charts and they are nice and easy to debug.
Here is some code that we have been working with on and off for a little while.
It works well, we have had a few users get it up and running, but I, nor PSG, cant support it, that said, if you need to send an email from a controller, and you have a little time, its probably worth you trying it.

Here is what the basic chart structure looks like;

As you can see, we simply check for an alarm (or an analog condition, or a variable going true or false or a…).
If its true, we check to see if we have sent an email once already. If not (as is the case the first time around), then send an email and set a variable true so that next time around, when the point is still on, the variable says, ‘hey, we have already sent one email, don’t send another’. (This is really [I]really[/I] [B]really[/B] important, you don’t want to send 1000’s of emails just because the point is still on… (Ask me how I know this…)
To send the email, we first load up a few addresses, here is whats in that block (#209 in the screen shot);

email servers IP address. Change to match yours.
Move String
From: 192.168.1.1
To: email_server_ip_address_string

Who the message is from:
Move String
From: someone@domain.com
To: email_from_address_string

who you are sending the email to:
Move String
From: mrsmith@domain.com.au
To: email_to_address_string

subject:
Move String
From: email subject for alarm 1
To: email_subject_string

body:
Move String
From: Email from a chart… How cool is that??
To: email_body_string

This is a very important step, it prevents you from sending 1000+ emails while the alarm point is in alarm. The email chart will set the flag true once the email has been sent, the user sets it false when the alarm is not longer active.
Move to Pointer
Object: email_alarm_1_sent_flag
Pointer: email_complete_ptr

Thats a cut and past from block ‘load message’. You can see the comments from each instruction. Yes, you could change it to an OptoScript block.

Now, the good stuff…
Here is the code that is in the OptoScript block (#198), the stuff that does all the talking to your email server…



  email_status_string = "";

  email_status_ok_continue_flag = 1; // set email_status_ok_continue_flag to true

  email_temp_string = "tcp:" + email_server_ip_address_string + ":25";

  SetCommunicationHandleValue(email_temp_string, email_server_com_handle);

  email_status_flag = OpenOutgoingCommunication(email_server_com_handle);

  email_server_delay = 0; // initialize the counter
    repeat 
    DelayMSec(100); // do a little loop waiting for the email server to answer our request.

    email_server_delay = email_server_delay + 1; // increment the counter
  until (email_server_delay >= 100) or (GetNumCharsWaiting(email_server_com_handle) > 0); // Either time out or the email server will answer.

  // Check the connection and receive the greeting
  if (0 == email_status_flag) then
    email_status_ok_continue_flag = 0; // assume an error

    if (GetNumCharsWaiting(email_server_com_handle) > 0) then
      DelayMSec(delay_short); 
      email_status_flag = ReceiveString(email_temp_string, email_server_com_handle);
       

      if (0 == email_status_flag) then
        if (FindSubstringInString("220", 0, email_temp_string) >= 0) then
          email_status_ok_continue_flag = 1;
        else
          email_status_string = email_temp_string;
        endif
      endif
    else
      email_status_string = "Unable to connect to email server";
    endif
  else
    email_status_string = "Unable to connect to email server";
  endif

  // Send Greeting
  if (email_status_ok_continue_flag) then

    GetControlEngineAddress(email_temp_string);

    email_send_string = "HELO " +  email_temp_string + Chr(13) + Chr(10);

    email_status_flag = TransmitString(email_send_string, email_server_com_handle);
    
    if (0 == email_status_flag) then
      if (GetNumCharsWaiting(email_server_com_handle) > 0) then
        email_status_flag = ReceiveString(email_temp_string, email_server_com_handle);

        if (0 == email_status_flag) then
          if (FindSubstringInString("250", 0, email_temp_string) >= 0) then
            email_status_ok_continue_flag = 1;
          else
            email_status_string = email_temp_string;
          endif
        endif
      endif
    endif
  endif


  // Send MAIL FROM
  if (email_status_ok_continue_flag) then
    email_status_ok_continue_flag = 0; // assume an error

    email_send_string = "MAIL FROM:" + email_from_address_string + Chr(13) + Chr(10);

    email_status_flag = TransmitString(email_send_string, email_server_com_handle);
    
    if (0 == email_status_flag) then
      if (GetNumCharsWaiting(email_server_com_handle) > 0) then
        email_status_flag = ReceiveString(email_temp_string, email_server_com_handle);
        if (0 == email_status_flag) then
          if (FindSubstringInString("250", 0, email_temp_string) >= 0) then
            email_status_ok_continue_flag = 1;
          else
            email_status_string = email_temp_string;
          endif
        endif
      endif
    endif
  endif


  // Send RCPT TO:
  if (email_status_ok_continue_flag) then
    email_status_ok_continue_flag = 0; // assume an error

    email_send_string = "RCPT TO:" + email_to_address_string + Chr(13) + Chr(10);

    email_status_flag = TransmitString(email_send_string, email_server_com_handle);
    
    if (0 == email_status_flag) then
      if (GetNumCharsWaiting(email_server_com_handle) > 0) then
        email_status_flag = ReceiveString(email_temp_string, email_server_com_handle);
        if (0 == email_status_flag) then
          if (FindSubstringInString("250", 0, email_temp_string) >= 0) then
            email_status_ok_continue_flag = 1;
          else
            email_status_string = email_temp_string;
          endif
        endif
      endif
    endif
  endif


  // Send DATA
  if (email_status_ok_continue_flag) then
    email_status_ok_continue_flag = 0; // assume an error

    email_send_string = "DATA" + Chr(13) + Chr(10);

    email_status_flag = TransmitString(email_send_string, email_server_com_handle);

    if (0 == email_status_flag) then
      if (GetNumCharsWaiting(email_server_com_handle) > 0) then
        email_status_flag = ReceiveString(email_temp_string, email_server_com_handle);
        if (0 == email_status_flag) then
          if (FindSubstringInString("354", 0, email_temp_string) >= 0) then
            email_status_ok_continue_flag = 1;
          else
            email_status_string = email_temp_string;
          endif
        endif
      endif
    endif
  endif

  // Send Subject, To, From, etc.
  if (email_status_ok_continue_flag) then
    email_send_string = "Subject:" + email_subject_string     + Chr(13) + Chr(10) + 
            "To:"      + email_to_address_string   + Chr(13) + Chr(10) + 
            "From:"    + email_from_address_string + Chr(13) + Chr(10) + Chr(13) + Chr(10);

    email_status_flag = TransmitString(email_send_string, email_server_com_handle);

    if (0 <> email_status_flag) then
      email_status_ok_continue_flag = 0;
    endif
  endif

  // Send Subject, To, From, etc.
  if (email_status_ok_continue_flag) then
    email_send_string = email_body_string + Chr(13) + Chr(10);

    email_status_flag = TransmitString(email_send_string, email_server_com_handle);

    if (0 <> email_status_flag) then
      email_status_ok_continue_flag = 0;
    endif
  endif


  // Send end of data
  if (email_status_ok_continue_flag) then
    email_status_ok_continue_flag = 0; // assume an error

    email_send_string = Chr(13) + Chr(10) + Chr(46) + Chr(13) + Chr(10);

    email_status_flag = TransmitString(email_send_string, email_server_com_handle);
 
    if (0 == email_status_flag) then
      if (GetNumCharsWaiting(email_server_com_handle) > 0) then
        email_status_flag = ReceiveString(email_temp_string, email_server_com_handle);
        if (0 == email_status_flag) then
          if (FindSubstringInString("250", 0, email_temp_string) >= 0) then
            email_status_ok_continue_flag = 1;
          else
            email_status_string = email_temp_string;
          endif
        endif
      endif
    endif
  endif


  if (email_status_ok_continue_flag) then
    email_status_string = "Message Sent";
    SetVariableTrue(*email_complete_ptr);
  endif

  CloseCommunication(email_server_com_handle);



That should get you up and running.
The nice thing about sending email from a chart using this code is that it can be sent from FactoryFloor controllers or newer.

There is one major ‘got-ya’ for any method (mem map or chart) that you might chose to use when sending emails from the controller with firmware versions less than v9.1…
There is no way to enter a user name or password to authenticate with the email server.

If you are on a company network with its own email server, you might need to talk with the IT guys and get them to whitelist the IP address of the controller sending the email. This means that they allow that IP address to relay emails from the controller without authentication.
If your controller is not on the same domain as the email server, and you want to use one out on the web, like yahoo or gmail, then there is only one thing I can suggest…
Subscribe to ‘OptoNews’ and wait… We might, just maybe, perhaps, have a solution to this authentication issue (and more) in the works…

In the mean time… Code on!


#2

Thanks Ben! I’ve been wondering how do to this… I can see this being very useful for some of our clients!


#3

In regard to the issue of not being able to authenticate, one of our users sent the following work around;
NOTE: Opto 22 does not do business with these people, its just a tip from someone who got it working with one of our controllers.

Note - This is feedback from a customer. I have never head of them until just now.

“I did find a solution yesterday. There is a company called “smtp2go”. They provide a service where I can have the (brain) send the email to their server and they don’t require a login and password. They charge $24 per year for up to 50 emails per day, which is more than sufficient.

Here is the email from them:

"… there is no software to ‘install’ with our service. You would simply change your SMTP server setting to smtp2go.com and your SMTP port to 2525 (or 25, 8025 or 587, if that doesn’t work).
If your device needs an IP address to send to, you can enter 207.58.142.213

The cost is $23.88/year.
https://www.smtp2go.com/signup/ "

So there you have it… Sounds reasonable.
If you contact them, lets know how you get on…

Cheers.


#4

Thanks Ben for the information. I tested it from smtp2go (free option) and it works very well.
There are a little error in the code line [136]. It is necesary change:

email_send_string = "Subject:" + email_server_ip_address_string     + Chr(13) + Chr(10) + 

for:

email_send_string = "Subject:" + email_subject_string     + Chr(13) + Chr(10) + 

#5

Edwin,

Thanks so much for the error check, (thats exactly what this part of the forum is about in my mind, helping each other to boldly go where no controller has gone before), I have made the change to the code.
Thanks also for the feed back on the smtp2go, nice to know that its a viable option.

Ben


#6

Update! Now you can use the built-in SendEmail commands, just get PAC Control 9.1 (along with the 9.1 firmware).
Here’s a sample chart to show how it works.

Hint: Don’t forget to configure your DNS & gateway IP addresses, and load your root certificate file.

Happy emailing!
-OptoMary


#7

Thanks Mary for the post, I just want to +++1 it and rave a little more about how this new command changes things…

In the past, we had a huge long chart that started out in Factory Floor. It worked, but was a bit touchy and was pretty cumbersome to work with.
Then came OptoScript, and we were able to pretty much put the one huge chart into one block. We could also do ‘in loop checks’ and this made sending an email a lot more reliable, but it still suffered three main issues;

  1. We could not send a password or username to authenticate with the email server.
  2. Sending a single email to many people was a hassle, those of us using this chart all came up with different ways to get around this.
  3. You could not send attachments.

The new email command in Pac Project 9.1 removes all three issues.

Yes, you read right, sending an email is now a simple Pac Control command!!!
(Having used the old chart for something like 8 years, I can barely contain my excitement at this new development).

Here is the command;
nResult = SendEmail(strtblServer, strtblRecipients, strtblBody);

You simply set up three string tables, put the necessary To: From: Subject: Body: Server: Username: Password: and so on in the right place in each table and call the command.
The docs (#1701 - Pac Control Command Reference) break it all down for you, its super easy.
Sending to many recipients is just a matter of putting their email address in the string table. You can have as many as you want (Hehe, can you imagine a spam bot from a pac controller??? Yeah, I’m kidding, just to make a point. Doing this is a great way to get your domain black listed, something you really don’t want).

Sending attachments is a different command, but pretty similar;
nResult = SendEmailWithAttachments(strServer, strRecipients, strBody, strAttach);

This is a great way to send log file data each night, each hour or whenever you want. Just log the data to a file on the controllers memory and send it when you want via email.

As Mary said, its now critical to do two things if you want to use this command;

  1. Put a valid DNS server IP address into your PAC Controller. It HAS to know how to resolve the domain name of your email server into an IP address (just like your computer has to every time you browse the web),
  2. Put the root certificate into the controllers memory in the right subdirectory and save it to flash AND REBOOT THE CONTROLLER. (I’m yelling at you so that you do as I tell you and not as I did (and then spend about an hour trying to figure why the email was not getting sent)… I saved to flash, but did not reboot, the root certificate is only unpacked and activated when the controller reboots).

I’m so happy to finally kill off this old chart way of sending emails. Of course if you have a Factory Floor controller, its still the only way, but its almost worth getting a Pac Controller just to send emails if you do a lot of it.
Another cool thing is that it works with PAC Basic, its not a pro feature, so you can send emails for free!

Ok, I need to stop raving and let you all go and download it and convert your strategies over…

One last thing, be sure to check out the other cool commands that 9.1 added while you are there… Looking forward to hearing about what cool things we get our PAC’s to do with the addition of these commands…


#8

I am having trouble getting the root cert to work.
I downloaded the equifax and installed it on the PC, only thing is I don’t know where it is.
So I extraced the exquifax cert and placed it on the desktop and uploaded it to the controller, saved it to flash and restarted, but I am still getting the -2104 error. Any suggestions?
Thanks


#9

Hello KJDingwall,

Welcome to the forums! That file has to go in a very specific place in your controller’s file system, in this sub-folder:
/pki/root-certs/
So when you’re doing the upload from PAC Manager, it should look something like this:

Also make sure you have your Gateway and DNS configured (0.0.0.0 is the default, which won’t work). That’s another common thing that trips people up.


If you have 0.0.0.0 for those values, select: Tools > Change IP Settings (in PAC Manager).

Hope that helps!
-OptoMary


#10

So everything works for me except that I get the 2104 error - which is an invalid root cert. I downloaded the equifax from the opto22 website link, and installed it but still get the same error


#11

Sorry, missed your post.
Working now, missed the full path on the cert download.
Thanks


#12

Excellent! One thing you’ll want to be careful with too is to make sure you have logic that will STOP the e-mails from going out over and over (like Ben mentions in the first post of this thread) so you don’t end up sending a whole ton of them and possibly causing mail servers to flag your emails as spam.

Happy e-mailing!


#13

Hi there,

I did exactly what you said, but the -2104 error comes up all the time, i uploded the EquifaxSecure certificate to the sub folder you specified , i upgraded the firmware, i am using pac 9.1c, the dns and gateway are configured…i dont know what to do!!! , PLEASE HELP…


#14

Thanks Guys, i figured out what the problem was!!!, i didn’t save the file to the flash…


#15

Hi Lawga,

Glad that you got it working… Just a note for others that follow in your footsteps… Not only do you have to save the certificate file to that special location, AND save the file to flash, BUT THEN you MUST REBOOT!!!
The reason is that the file is only extracted and copied to RAM when the controller is rebooted.

Email on !

Ben.


#16

Cannot get text messaging to work with sprint (MobilNumber@messaging.sprintpcs.com). We have been using At&t text messaging with no problems. Any advice?


#17

Hi Tim,

I just tested the service from my email on my PC to my phone and it worked straight away…
So, I suggest that you break it down a bit.
Try it from a PC or laptop email client on the same network as the controller.
Once you are confident that is working ok, then turn your attention to the controller strategy and settings.
Remember, you must set the DNS and Gateway on the controller via PAC Manager.
Since it was working… what changes have been made other than the email address?

Ben.


#18

Ben,

Thank you for your advice. Sending email using PC to phone has always been working on the network the controller is using. However, I can never send text message within the strategy. I know that DNS and Gateway on the controller is set correctly because it can send text message to AT&T phone but not to Sprint (all content sent to both cell phone are identical). If you can test it in your test strategy and see if you have the same problem.

System Set-up:
Controller type: R2
PAC Basic 9.2
Network: Remote Access - Controller to wireless router with aircard (Sprint)
Router: Proxicast

Thanks,
Tim


#19

We do a fair bit of text messaging and emailing with our controllers. We had an issue about a year ago where it suddenly stopped working on a client’s system. Turns out that the client had switched their phones to a different carrier (Rogers up here in Canada) and that carrier no longer supports email-to-text capabilities. It still works on most carriers up here but Rogers no longer does.

The simplified bottom line was Rogers doesn’t like third party email-to-text commands running through their servers (such as an outside request from an Opto controller) and blocked/stopped supporting it.

The way we got around it was by setting up email addresses for all the message recipients and dropping the email polling/push settings on their phones really low (I think default on an iPhone is 15mins… by that time you could have a lot of trouble on your hands!!). Not an ideal solution but it works.

If it doesn’t work to send an email to the phone (10digitphonenumber@messaging.sprintpcs.com is what I’m showing as the correct addressing) from a PC, there’s a good chance you’re in the same boat that I was. However it sounds like you have that working. I have a simple test strategy running on our in-house test rack that I use to test email-to-text functionality. If you send me a message with the phone number in question, I can certainly shoot it a test message through our mail server and let you know the result.


#20

Hi Tim,

Sorry you’re having trouble. I tried sending (via my gmail account) to several email addresses including the text message address of my Verizon cell phone (10digits@vtext.com) and a borrowed Sprint phone. Sprint message never showed up (like you saw) but all the others did. So did emailing from a regular email account, like you saw.

Also, I sent Arlin (thanks for volunteering your email server, Arlin!) this Sprint number. In the past we’ve had luck sorting out such issues when another kind OptoForum user was able to send the detailed information their email server got back, so I’m hoping Arlin will see some clues coming back from messaging.sprintpcs.com.

In the meantime, I could tell you a few other things I don’t like about Sprint, but I’ll refrain. I’m liking Verizon even more now!

Thanks,
Mary