SendGrid Webhook Callback on Local Machine

Testing SendGrid webhook call back on live Webhook testing sites such as Webhook.site is good for starters, but to actually use the webhook in production, a lot of other code is required, such as validating data, updating the database, etc.

It would be better if SendGrid Webhook Api Call can be redirected to the local machine of developers.

For this. Live Url Software like Ngrok is useful.

Ngrok will temporarily provide a live URL of the local machine, which can be accessible publically.

Get Started with ngrok

ngrok

Ngrok allows temporarily exposing a local machine running webserver to the internet.

Download from https://ngrok.com/download

Unzip the file on Linux OS using unzip /path/to/ngrok.zip or double click on Windows OS.

Create an Account or Login and get your authentication token from https://dashboard.ngrok.com/get-started/your-authtoken

Navigate to the setup file, open the command prompt.

Authenticate account

on Linux OS run ./ngrok authtoken <your_auth_token>
on Wndows OS ngrok authtoken <your_auth_token>

Fire Up Server

on Linux OS run ./ngrok http 8080
on Windows OS ngrok http 8080

ngrok will tunnel HTTPS and HTTP to the local machine with the port provided and display the temporary URL

Publically Accessible URL   Local Machine Server URL
http://de95-xxx-xx-xx-xxx.ngrok.io   http://localhost:8080
https://de95-xxx-xx-xx-xxx.ngrok.io   http://localhost:8080

Along with the above, Ngrok provides a Web Interface at http://127.0.0.1:4040

package org.wesome.sendgrid;

import com.sendgrid.SendGrid;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
public class SendGridApplication {
    @Value("${send.grid.api.key}")
    private String sendGridApiKey;

    public static void main(String[] args) {
        SpringApplication.run(SendGridApplication.class, args);
    }

    @Bean
    public SendGrid sendGrid() {
        SendGrid sendGrid = new SendGrid(sendGridApiKey);
        return sendGrid;
    }
}
package org.wesome.sendgrid.controller;

import com.sendgrid.Method;
import com.sendgrid.Request;
import com.sendgrid.Response;
import com.sendgrid.SendGrid;
import com.sendgrid.helpers.mail.Mail;
import com.sendgrid.helpers.mail.objects.Content;
import com.sendgrid.helpers.mail.objects.Email;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.util.List;
import java.util.Map;

@RestController
public class SendGridController {
    private static final String TO_EMAIL = "[email protected]";
    private static final String X_MESSAGE_ID = "X-Message-Id";
    private static final String FILTER = ".filter";
    private static String MESSAGE_ID;
    @Autowired
    private SendGrid sendGrid;

    @PostMapping("webhook")
    public void webhook(@RequestBody List webhook) {
        for (WebHook webHook : webhook) {
            String messageId = webHook.getSg_message_id();
            messageId = messageId.substring(0, messageId.indexOf(FILTER));
            if (MESSAGE_ID.equalsIgnoreCase(messageId)) {
                System.out.println("Mail sent to " + TO_EMAIL + " is " + webHook.getEvent() + "\n");
                System.out.println("webHook = \n" + webHook);
            }
        }
    }

    @GetMapping("/send")
    public ResponseEntity sendMail() throws IOException {
        Email from = new Email("[email protected]");
        String subject = "WeSome.Org";
        Email to = new Email(TO_EMAIL);
        Content content = new Content("text/plain", "I am learning SendGrid from WeSome.Org because its fun");
        Mail mail = new Mail(from, subject, to, content);
        Request request = new Request();
        Response response;
        try {
            request.setMethod(Method.POST);
            request.setEndpoint("mail/send");
            request.setBody(mail.build());
            response = sendGrid.api(request);
            Map headers = response.getHeaders();
            MESSAGE_ID = headers.get(X_MESSAGE_ID);
            System.out.println("Headers := \n" + response.getHeaders());
            System.out.println("message id := \n" + MESSAGE_ID);
            System.out.println("Body := \n" + response.getBody());
            System.out.println("StatusCode := \n" + response.getStatusCode());
        } catch (IOException ex) {
            throw ex;
        }
        return new ResponseEntity(HttpStatus.valueOf(response.getStatusCode()).getReasonPhrase(), HttpStatus.valueOf(response.getStatusCode()));
    }

    @GetMapping("webhook/settings")
    public ResponseEntity sendGridAPI() throws IOException {
        Request request = new Request();
        Response response;
        try {
            request.setMethod(Method.PATCH);
            request.setEndpoint("user/webhooks/event/settings");
            request.setBody("{ \"group_resubscribe\": true, \"delivered\": true, \"group_unsubscribe\": true, \"spam_report\": true, \"url\": \"https://de95-103-112-17-103.ngrok.io/webhook\", \"enabled\": true, \"bounce\": true, \"deferred\": true, \"unsubscribe\": true, \"dropped\": true, \"open\": true, \"click\": true, \"processed\": true }");
            response = sendGrid.api(request);
            System.out.println("Headers := \n" + response.getHeaders());
            System.out.println("Body := \n" + response.getBody());
            System.out.println("StatusCode := \n" + response.getStatusCode());
        } catch (IOException ex) {
            throw ex;
        }
        return new ResponseEntity(HttpStatus.valueOf(response.getStatusCode()).getReasonPhrase(), HttpStatus.valueOf(response.getStatusCode()));
    }
}
plugins {
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    id 'org.springframework.boot' version '2.5.5'
    id 'java'
}

group = 'org.wesome'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = JavaVersion.VERSION_1_8

repositories {
    mavenCentral()
}
dependencies {
    implementation 'com.sendgrid:sendgrid-java:4.4.5'
    implementation('org.springframework.boot:spring-boot-starter-web')
}

test {
    useJUnitPlatform()
}
send.grid.api.key=Your SendGrid Api Key
curl --location --request GET 'http://localhost:8080/webhook/settings'
curl --location --request GET 'http://localhost:8080/send'

follow us on