Webhook Tutorial - Send an Email!

Hello everyone,

Recently I’ve been working on a IoT Water Tank level sensor to measure the water level for a small water tower. When the water level gets low the Photon in my project sends out an event and I needed away to push that event to my devices. So that I could easily filter the event I decided to have the event trigger a webhook which would, in turn, send out an email. When I couldn’t find an email webhook I wrote one myself. Tutorial/instructions below. It takes about 10 minutes to get through it.

  1. Head on over to mailgun and register for an account.
  2. Login and take a look at your mailgun dashboard.
  3. You should see an active sandbox domain. You can add your own, custom, domain but that is outside the scope of this tutorial. Click on the link for your sandbox domain.
  4. You should now see a page with information for your sandbox domain. You want to make sure to write down / save the following two values from this page “API Base URL” and “API Key”.
  5. Navigate to the Particle Dashboard Integration Page.
  6. Select “New Integration” and then “Webhook”.
  7. Click “Custom JSON” in the top right of the page.
  8. In a new tab grab the contents of this file and paste into the Custom JSON text box on the new Webhook page
  9. Fill in the all values which are IN_ALL_CAPS as follows
  • EVENT_PREFIX - This is your event name or prefix.
  • MAILGUN_API_BASE_URL - This is the API Base URL from earlier.
  • MAILGUN_API_KEYKEY - This is the API Key from earlier
  • TO_EMAIL - This is the email you want to send an email to. Example would be "name@email.com"
  • ANY_NAME - This is literally anything you want. I call mine “Particle Webhook Bot”
  • ANY_EMAIL_ADDRESS - This can again be anything. I use “particle”
  • MAILGUN_SANDBOX_DOMAIN - This is your sandbox domain
  • ANY_SUBJECT - This is the subject of the email
  • ANY_BODY - This is the body of the email
  1. Click “Create Webhook”.
  2. Send an event from one of your devices (or the CLI) with an event name which either starts with EVENT_PREFIX or is EVENT_PREFIX
  3. You should receive an email. :slight_smile:

If you have any issues feel free to post here and I’ll try to help!

9 Likes

Thanks this is a great Tutorial and has been very helpful. Is it possible instead of using particle.publish we could use particle.function to send the event just the once or would you just run this code outside the loop?

Thanks once again…Ben

You need to push the event from your device via Particle.publish() but that can still be triggered via a Particle.function() from outside.

Particle.function()s receive data from the outside world while Particle.publish() pushes data out into the world.

Thanks for your reply.
I don’t think that is what i am looking for.
What i am trying to do is, when an input becomes low an event is sent triggering an email to be sent, (which is currently working thanks to this Tutorial) however to stop my code from sending a massive amount of emails, i have to include a timer within the code. this is then inhibiting the code from looking for another instance of a low input. as i am relatively new to programming i am unsure of the best way to do this, i was thinking my Electron would create an instance of a function outside the loop which would then be seen by the mailgun and send the email just the once or am i going the wrong way about it.
Eventually i want to put the Electron into a sleep and disconnect from the cloud then wake up, connect to the cloud to send the alarm and go back to sleep (to conserve battery and data. but i will take one hurdle at a time.

(SORRY i have forgotten how to format the code and can not find it in the guide so if you could inform me that would be great)

thanks…Ben

int Alarm1 = D4; // high float will be connected to pin d2 on the unit
int highlevellight = D7;

void setup() 
{
//pinMode(highfloat, INPUT_PULLUP);// declare that pin an INPUT
pinMode(Alarm1, INPUT_PULLDOWN);
/*If the float switch connects D3 to 3V3 and is open when the level is high:
pinMode(highfloat, INPUT_PULLDOWN) is required instead.
And: if (digitalRead(highfloat) == LOW)
*/
pinMode(highlevellight, OUTPUT);// declare the highlevellight pin as an output
//highfloat = LOW; // set the input as low to make sure  the program is not started with it on
//highlevellight = HIGH;
}

void loop() {
       if (digitalRead(Alarm1) == LOW)
    {
   // Particle.publish("EVENT_PREFIX");
    Particle.publish("EVENT_PREFIX", PRIVATE);
  // Particle.function("EVENT_PREFIX", PRIVATE);
    digitalWrite(highlevellight, LOW);
 
    delay(600000);
    }
    else
    {
    digitalWrite(highlevellight, HIGH);
    }
    delay(1000);
   
}

You mean something like this?

int Alarm1 = D4; // high float will be connected to pin d2 on the unit
int highlevellight = D7;
bool isArmed = true;

int rearm(String dmy)
{
  isArmed = true;
  return 0;
}

void setup() 
{
  Particle.function("rearmAlarm", rearm);

  pinMode(Alarm1, INPUT_PULLDOWN);
  pinMode(highlevellight, OUTPUT);// declare the highlevellight pin as an output
}

void loop() 
{
  bool state = !digitalRead(Alarm1);  // invert active LOW to more intuitive active HIGH
  if (isArmex && state)
  {
    isArmed = false;  // don't trigger till rearmed
    Particle.publish("EVENT_PREFIX", PRIVATE);
  } 
  digitalWrite(highlevellight, state);
}

Here you can find some formatting hints
Forum Tips and Tricks

i think so there is a few things i dont understand
to re-arm the alam would i have to send a function from somewhere lets say a webpage??

int Alarm1 = D4; // high float will be connected to pin d2 on the unit
int highlevellight = D7;
bool isArmed = true;

int rearm(String dmy)  ////////////////is this when we run the function it sets the alarm again ready to be activated
{
  isArmed = true;
  return 0;
}

void setup() 
{
  Particle.function("rearmAlarm", rearm); 

  pinMode(Alarm1, INPUT_PULLDOWN);
  pinMode(highlevellight, OUTPUT);// declare the highlevellight pin as an output
}

void loop() 
{
  bool state = !digitalRead(Alarm1);  // invert active LOW to more intuitive active HIGH /////// is this state is asigned the oposite of Alarm1 so if it is low state will be TRUE?????
  if (isArmex && state)    /////// is this if isArmed and state is true 
  {
    isArmed = false;  // don't trigger till rearmed
    Particle.publish("EVENT_PREFIX", PRIVATE);
  } 
  digitalWrite(highlevellight, state);
}
[/quote]

Yes that's the idea, although that could be called multiple ways, not only from a web page.

You could also rearm after a given time by use of a timer in your code.

And the answer to both your comments in the code is: Yes

I actually use a small button on my board to silence my “alarm” and then it automatically re-arms when it goes out of the alarm state for a given amount of time. That would be one option. You could also just have it re-arm when it leaves the alarm state.

Thanks. As my electron will be remote. I will have to get it to rearm itself when the state becomes healthy again and possibly send a system healthy alarm which I should be able to do. Is there a way that if the electron goes offline an email can be sent ?

There is no way to do this with just the Particle ecosystem. What you are looking for is something like a health monitor. A health monitor would periodically ping the device (ie, call a function or do a variable call) and if it did not receive a response it would emit a Particle Event to call a webhook.

I just wrote this tutorial on how to build a health monitor of sorts

ok thanks for all the replies and suggestions. below the code i have working thanks scruffr… so we get an email when alarm is active and also when the state becomes healthy again, and as it only sends one message every time i would think it would be pretty easy on the data (or is there a way i could save more data). as this maybe running on batteries would this code be quite power hungry ?? would it be better to take a different approach.

Any suggestions and code criticism welcome

thanks…Ben

//Alarm system which is activated when input becomes LOW 
//if the alarm is activated and waiting for a low input then led d7 will flash on and off every second
//if a low input is detected then the led on d7 will flash one cycle at 0.5seconds then stay on
//



int Alarm4 = D4; // high float will be connected to pin D4 on the unit
int highlevellight = D7; //this is the light that will give us info about the state of the alarm
bool isArmed = true;       //true or false is the alarm set
int i;                     // integer to count 1 time so multiple set emails are not sent

//int rearm(String dmy)  ////////////////is this when we run the function it sets the alarm again ready to be activated
//{
 // isArmed = true;
 // return 0;
//}

void setup() 
{
 // Particle.function("rearmAlarm", rearm); 

  pinMode(Alarm4, INPUT_PULLDOWN);
  pinMode(highlevellight, OUTPUT);// declare the highlevellight pin as an output
  i = 0;
}

void loop() 
{
    if (isArmed == true && i<1)
    {
        {
        Particle.publish("ALARM_SET", PRIVATE); // publish the event so alarm set email can be sent
       ////// flash the lights so we know alarm is armed--------------------------------------------
        digitalWrite(highlevellight, LOW);
        delay (1000);
        digitalWrite(highlevellight, HIGH);
        delay(1000);
        digitalWrite(highlevellight, LOW);
        delay (1000);
        digitalWrite(highlevellight, HIGH);
        delay(1000);
        digitalWrite(highlevellight, LOW);
        delay(1000);
        digitalWrite(highlevellight, HIGH);
        delay (1000);
        digitalWrite(highlevellight, LOW);
        i++; //add one to i so the code will not be run again
        
             
        }
    
        
    }
    
  bool state = !digitalRead(Alarm4);  // invert active LOW to more intuitive active HIGH /////// state is asigned the oposite of Alarm1 so if it is low state will be TRUE
  if (isArmed && state)    /////// if isArmed and state is true 
  {
    isArmed = false;  // don't trigger till rearmed
    Particle.publish("EVENT_PREFIX", PRIVATE); // publish the event so an email can be sent
        
        /////////////Flash light to indicate an alarm state////////////////////////////////
        digitalWrite(highlevellight, LOW);
        delay (500);
        digitalWrite(highlevellight, HIGH);
        delay(500);
        digitalWrite(highlevellight, LOW);
        delay (500);
         digitalWrite(highlevellight, HIGH);
        delay(500);
        digitalWrite(highlevellight, LOW);
        delay (500);

  
  }
  
  if (!isArmed && !state) //if thr alarm is not armed and the state is false the alarm is not activated (not LOW)
  {
      i = 0; //set i back to 0 so the alarm active email can be sent once
      isArmed = true; // set isArmed to true  so the alarm process can be run again
  }

  
}

To save power, you could use sleep that wakes on an interrupt triggered by your sensor.

so i would not use the wake up pin i would just used a normal DI pin which wakes up the program?

Yup, any pin that can be used with System.sleep(wkp, trigger) but with WKP you could also use System.sleep(SLEEP_MODE_DEEP) (but only for RISING edge).

Hi @harrisonhjones,

thank you very much for this great tutorial! :smile:
Would it be possible to change the subject and body of the email in a kind of flexible way?
For example including the temperature in the body?

Yes, it should be possible. Here is, roughly, what you would need to do:

First: Edit the JSON file I linked to. Replace

subject: "ANY_SUBJECT",
text: "ANY_BODY"

with

subject: "{{s}}",
text: "{{b}}"

Second: Publish an event with a body/payload that looks like this:

"{\"s\":\"Your subject here\", \"b\":\"Your body here\"}"

2 Likes

Thank you very much for your help! I have adapted your example and it is working great :smile:
It would be cool to be able to edit Webhooks instead of heaving to delete them everytime I want to change something.

Thanks @harrisonhjones for a great tutorial. Got this working with only a minimum of false starts.

Very minor suggestion (to make things crystal clear for the newbies like me): Step 8: Paste the text of the linked file over (replace entirely) the default text that appears in the JSON text editor. …yes I know obvious…who would make such a mistake… :flushed:

Suggestions/comments for those coming after:

  1. Because if you make an error in your JSON text and your webhook doesnt work as you intended it to, you will need to delete and reinstate your webhook. Yes, you heard it right, at present you cannot edit your webhook. So I learned pretty quickly you need that JSON text saved in Notepad or your favourite text editor equivalent, so you can re-create your webhook easily.

  2. Mailgun has great documentation and logs and seems to clearly explain what the errors are you may have made in the JSON text (if any). If you get errors returned from Mailgun they will show up in the Particle Console Logs tab. To debug, best to go into Mailgun and track through the logs/diagnostics. To do this go to the “Logs” screen and click on a message/log event. The details will drop down.

1 Like

@benjiiiuk:

Check out IFTTT. I use it to monitor a number of Particle devices and I can get an email when the device goes offline and then again when it comes back online.

Just to help summarise, I found it a bit tricky to follow myself. So here is an example that is easily reusable.

Part 1: Write a Particle.publish() on the Particle device to trigger the webhook to activate
Part 2: Write a webhook on the console.particle.io page which sends a message to the Mailgun API
Part 3: Mailgun API - some tips

Part 1: White a Particle.publish()
I used this code in the ‘setup’ (e.g. void setup() ) section to trigger the Publish only once.
Why? So it only runs each time the device starts.

Tip: Careful here as if the device gets stuck in a reboot loop (e.g. your watchdog timing isn’t right) you could end up sending a lot of emails overnight and not notice. So be sure to setup some limits on your Mailgun account.

Here the is Particle.Publish I used to trigger my webhook.

//DEVICE BOOTED - EMAIL NOTIFICATION
        String msgBody = String("From device:" + String(anotherVariableIHadElseWhereInMyCode) + ", ModuleId: " + String(anotherVariableNameIHadElsewhereInMyCode) + "It is alive now");

        sendEmailViaWebhook("my-email-address-was-here@gmail.com", "BOOT ADVISORY MESSAGE", String(msgBody));

The first bit ‘String msgBody’ - let’s you put a whole let of Strings together and put it into the message body.
The second bit 'sendEmailViaWebhook - is code that calls a function that is in my code. Why use a function? It let’s me re-use that same email sending ability later, so I don’t have to keep re-writing the next bit…

This bit was placed AFTER the loop() { }

The function on the particle device that sends the command to the web hook.

//This bit declares the function
int sendEmailViaWebhook(String input_to_email, String input_subject, String input_body)
    {
        //This bit wraps all of the various bits into one single String (into what is called JSON format)
        //Don't worry - we this single string is in a format called JSON which the Webhook & Mailgun API knows how to unwrap
        String publishData = String::format(
                	        "{ \"TO_EMAIL\": \"%s\", \"SUBJECT\": \"%s\", \"BODY\": \"%s\" }",
                	        input_to_email.c_str(), input_subject.c_str(), input_body.c_str());
       
       //We use a 'Publish' to send our JSON 'string' or 'message' to our Webhook called 'myMailgunEvent'     
       Particle.publish("myMailgunEvent", publishData, PRIVATE))
        

        return 0;
    }

Part 2: Write a webhook on the console.particle.io page which sends a message to the Mailgun API
They did a good job of explaining this above, but to show you exactly what worked with the same code I used above, use this below.

Step 1: Go to console.particle.io
Step 2: Go to integrations (icon on left hand side)
Step 3: Click 'new integration’
Step 4: Select 'webhook’
Step 4: Select custom template
Step 5: Delete all of the existing text in the box that appears
Step 6: Copy in the text below:

BEFORE you copy it in, remember to change these key parts:
YOURDOMAINGOESHERE = putyourdomainnamehere.com
YOURKEYGOESHERE = the api key that is written in Mailgun’s domain page.

 {
        "event": "myMailgunEvent",
        "url": "https://api.mailgun.net/v3/YOURDOMAINGOESHERE/messages",
        "requestType": "POST",
        "noDefaults": true,
        "rejectUnauthorized": false,
        "form": {
            "to": "{{TO_EMAIL}}",
            "from": "Notifications <Notifications@YOURDOMAINGOESHERE>",
            "subject": "{{SUBJECT}}",
            "text": "{{BODY}}"
        },
        "auth": {
            "username": "api",
            "password": "YOURKEYGOESHERE"
        }
    }

Part 3: Mailgun API - some tips

  • Make sure you click the email confirmation to validate your Mailgun account, you can’t send emails until you do this
  • It helps to try send basic text emails first - fancy formatting is a bit harder, do this later.

If you need any help - feel free to message below.

PS: You don’t need to use a function, you could put all the code in step 1 in the same area, but if you want to use it a few times in various places, it will save you a lot of space/time.

2 Likes