A story confirming the implementation of the SendGrid Java library when mail delivery fails

Preface

I'm writing a web application in Java. I'm using SendGrid to deliver mail from the system, but if mail delivery fails for some reason, after assuming Since the processing was moss, I will write it as a memorandum. ~~ All were implementations that arose from the predecessor's belief that "Response will return results even in the event of an error." ~~

Create an email delivery process using SendGrid

Install SendGrid Java Library in your project in build.gradle and create an email sending method. If SendGrid returns an error in the 400s, it will not be retried due to an inadequate request parameter sent from here or an excess request, leaving a log and returning error information to the front side to end the process. In the case of the 500 series, there is an error in the SendGrid server, so I created it to retry 2-3 times. I will omit the code around the retry (sorry).

Reference: SendGrid: Status Codes and Errors

dependencies {
    compile ('com.sendgrid:sendgrid-java:4.0.1')
}
import com.sendgrid.*;
import java.io.IOException;

public class Example {
  public static void main(String[] args) throws IOException {
    SendGrid sg = new SendGrid(System.getenv("SENDGRID_API_KEY"));
    try {
      Request request = new Request();
      request.setMethod(Method.GET);
      request.setEndpoint("api_keys");
      Response response = sg.api(request);
      if (response.getStatusCode() < 300) {
            //200 series continues processing as normal transmission
      } else if (response.getStatusCode() < 500){
            //For 400 series error, the request parameter is judged to be invalid and processing ends.
            //Leave a log and return the error message to the front
      } else {
            //500s error is a SendGrid server error and retries several times
            //Keep the log
      }
    } catch (IOException ex) {
      throw ex;
    }
  }
}

The problem that the expected processing is not performed

I created it so that the status code in the response returned as above is judged and the subsequent processing is distributed ~~ (predecessor) ~~. There is a flaw in the validation check process when composing an email, post-processing is not performed when the email cannot be sent, and the expected log does not remain, so it turns out that this implementation is flawed.

Check the implementation

Follow the api () method of the com.sendgrid.SendGrid class to see where you're actually sending your request to SendGrid. (Omitted because you can reach it in 3-4 steps)


private Response executeApiCall(HttpRequestBase httpPost) throws IOException {
	try {
		CloseableHttpResponse serverResponse = httpClient.execute(httpPost);
		try {
			Response response = getResponse(serverResponse);
			if(response.getStatusCode() >= 300) {
				//throwing IOException here to not break API behavior.
				throw new IOException("Request returned status Code "+response.getStatusCode()+"Body:"+response.getBody());
			}
			return response;
		} finally {
			serverResponse.close();
		}
	} catch(ClientProtocolException e) {
		throw new IOException(e.getMessage());
	}
}

You can see that the com.sendgrid.Client class has an executeApiCall () method that executes () on the 3rd line, and above all, the if statement on the 6th line throws an IOException. Even if the status code is greater than 300, you can fill the response with that value and return it. .. ..

SebdGrid return value and then

Caused by: java.io.IOException: Request returned status Code 400Body:
{
    "errors": [
        {
            "message": "Invalid replyTo email address",
            "field": "reply_to",
            "help": null
        }
    ]
}

SendGrid returns an error message as above, so I should have written the follow-on processing from the caught IOException instead of the response. In addition, in consideration of the fact that SendGrid is unlikely to have a large-scale failure for the past 1-2 years and the usage rate of emails, the retry process has been deleted and an error message has been displayed quickly (validation check has been fixed). So the 400s error shouldn't occur!).

Miscellaneous feelings

It was a suspicious case where my beliefs and various tests were inadequate, but it was an event that I learned to check the return value of the library used and use it.

Recommended Posts

A story confirming the implementation of the SendGrid Java library when mail delivery fails
[Java] When writing the source ... A memorandum of understanding ①
[Java version] The story of serialization
A story about hitting the League Of Legends API with JAVA
The story of forgetting to close a file in Java and failing
The story of making a game launcher with automatic loading function [Java]
[Java small story] Monitor when a value is added to the List
The story of writing Java in Emacs
The story of low-level string comparison in Java
The story of making ordinary Othello in Java
A story about the JDK in the Java 11 era
The story of learning Java in the first programming
Measure the size of a folder in Java
The story of initializing Money :: Currency when testing
A story that people who did iOS solidly may be addicted to the implementation of Listener when moving to Android
The story of making a reverse proxy with ProxyServlet
Awesome Java: A number of great Java framework library software
A survey of the Kubernetes native Java framework Quarkus
The story of making dto, dao-like with java, sqlite
The story of building a Java version of Minecraft server with GCP (and also set a whitelist)
A quick explanation of the five types of static in Java
20190803_Java & k8s on Azure The story of going to the festival
A story packed with the basics of Spring Boot (solved)
[Java] Simplify the implementation of data history management with Reladomo
Implementation of a math parser with recursive descent parsing (Java)
Traps brought about by the default implementation of the Java 8 interface
About the behavior when doing a file map with java
The story of pushing Java to Heroku using the BitBucket pipeline
The story of making a binding for libui, a GUI library for Ruby that is easy to install
Comparison of version strings (Java implementation) when you want to branch the process between two versions
A story that made me regret when a "NotReadablePropertyException" occurred during the development of the Spring Boot application.