King-Wizard King-Wizard - 7 months ago 50
Java Question

Why do I get this error when I try to send an email containing inline image (using Jersey 2 REST client and Mailgun webservice for sending emails)?

Using Jersey 2 (Java rest framework) with Mailgun webservice and get an error when I try to send email containing inline image.

According to the Mailgun's documentation below (using an out-of-date version of the jersey API: V1.8)

Mailgun's out-of-date documentation source code link

/*
Sending Inline Images
Mailgun assigns content-id to each image passed via inline API parameter, so it can be referenced in HTML part.
Example of sending inline image. Note how image is referenced in HTML part simply by the filename:
*/
public static ClientResponse SendInlineImage() {
Client client = Client.create();
client.addFilter(new HTTPBasicAuthFilter("api",
"key-3ax6xnjp29jd6fds4gc373sgvjxteol0"));
WebResource webResource =
client.resource("https://api.mailgun.net/v2/samples.mailgun.org" +
"/messages");
FormDataMultiPart form = new FormDataMultiPart();
form.field("from", "Excited User <me@samples.mailgun.org>");
form.field("to", "baz@example.com");
form.field("subject", "Hello");
form.field("text", "Testing some Mailgun awesomness!");
form.field("html", "<html>Inline image here: <img src=\"cid:test.jpg\"></html>");
File jpgFile = new File("files/test.jpg");
form.bodyPart(new FileDataBodyPart("inline",jpgFile,
MediaType.APPLICATION_OCTET_STREAM_TYPE));
return webResource.type(MediaType.MULTIPART_FORM_DATA_TYPE).
post(ClientResponse.class, form);
}


I tried to translate the code above using Jersey V2 api (please find my personal source code below):

public class JerseyClientExamples {

private static Logger LOG_TO_CONSOLE = Logger.getLogger("toConsole");
private static Logger LOG_TO_FILE = Logger.getLogger("toFile");

// OK
private String getValidBasicAuthenticationStrEncrypted() {
String strValidLoginClear = PropertyUtility.getProperty(
PropertyType.WEB_SERVICE_CREDENTIALS, "LOGIN");

String strValidPasswordClear = PropertyUtility.getProperty(
PropertyType.WEB_SERVICE_CREDENTIALS, "PASSWORD");

String strValidLoginAndPasswordEncrypted = new StringBuilder()
.append("Basic ")
.append(Base64.encodeBase64URLSafeString(new StringBuilder()
.append(strValidLoginClear).append(":")
.append(strValidPasswordClear).toString().getBytes()))
.toString();

return strValidLoginAndPasswordEncrypted;
}

public static void main(String[] args) {
JerseyClientExamples jerseyClientExamples = new JerseyClientExamples();
jerseyClientExamples.sendingInlineImage();
}

public void sendingInlineImage() {
Client client = ClientBuilder.newBuilder().register(MultiPartFeature.class).build();
HttpAuthenticationFeature feature = HttpAuthenticationFeature.universalBuilder()
.credentialsForBasic("api", "key-myPersonalKey")
.build();
client.register(feature);

WebTarget target = null;
try {
target = client
.target("https://api.mailgun.net/v2/yoloz.com")
.path("messages");
} catch (IllegalArgumentException | NullPointerException e) {
LOG_TO_CONSOLE.fatal(e, e);
LOG_TO_FILE.fatal(e, e);
}

Builder builder = target.request(MediaType.MULTIPART_FORM_DATA);

FormDataMultiPart form = new FormDataMultiPart();
form.field("from", "Abdul from Yoloz <abdul@yoloz.com>");
form.field("to", "ludivine.vanbasten@gmail.com");
form.field("subject", "The bouyakasha image show");
form.field("text", "Here you have the image.");

form.field("html", "<html>Inline image here: <img src=\"cid:back2-mini.jpg\" /></html>");
File jpgFile = new File(System.getProperty("user.dir") + "/src/main/resources/images/back2-mini.jpg");
if(jpgFile.exists() && !jpgFile.isDirectory()) { System.out.println("File exists !!!"); }
form.bodyPart(new FileDataBodyPart("inline", jpgFile, MediaType.APPLICATION_OCTET_STREAM_TYPE));
Response response = builder.post(Entity.entity(form, MediaType.MULTIPART_FORM_DATA_TYPE));

LOG_TO_CONSOLE.debug(response.getStatus());
LOG_TO_CONSOLE.debug(response.readEntity(String.class));
}

}


Please find below the dependencies that I use in my pom.xml:

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>

...

<jersey.container.version>2.13</jersey.container.version>
<jackson.version>2.4.3</jackson.version>
<genson.version>1.1</genson.version>
<jongo.version>1.1</jongo.version>
</properties>

<dependencies>

...

<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>${jersey.container.version}</version>
</dependency>

<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>${jersey.container.version}</version>
</dependency>

<!-- Required only when you are using JAX-RS Client -->
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>${jersey.container.version}</version>
</dependency>

<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0.1</version>
</dependency>

<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>2.13</version>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson.version}</version>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson.version}</version>
</dependency>

<dependency>
<groupId>org.jongo</groupId>
<artifactId>jongo</artifactId>
<version>${jongo.version}</version>
</dependency>
</dependencies>


Everytime that I run my jersey 2 rest client:

public static void main(String[] args) {
JerseyClientExamples jerseyClientExamples = new JerseyClientExamples();
jerseyClientExamples.sendingInlineImage();
}


For this particular instruction below:

Line 152: Response response = builder.post(Entity.entity(form, MediaType.MULTIPART_FORM_DATA_TYPE));


I got the error below:

File exists !!!
oct. 20, 2014 5:16:08 AM org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor aroundWriteTo
GRAVE: MessageBodyWriter not found for media type=multipart/form-data, type=class com.sun.jersey.multipart.FormDataMultiPart, genericType=class com.sun.jersey.multipart.FormDataMultiPart.
Exception in thread "main" org.glassfish.jersey.message.internal.MessageBodyProviderNotFoundException: MessageBodyWriter not found for media type=multipart/form-data, type=class com.sun.jersey.multipart.FormDataMultiPart, genericType=class com.sun.jersey.multipart.FormDataMultiPart.
at org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor.aroundWriteTo(WriterInterceptorExecutor.java:247)
at org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:162)
at org.glassfish.jersey.message.internal.MessageBodyFactory.writeTo(MessageBodyFactory.java:1154)
at org.glassfish.jersey.client.ClientRequest.writeEntity(ClientRequest.java:503)
at org.glassfish.jersey.client.HttpUrlConnector._apply(HttpUrlConnector.java:315)
at org.glassfish.jersey.client.HttpUrlConnector.apply(HttpUrlConnector.java:227)
at org.glassfish.jersey.client.ClientRuntime.invoke(ClientRuntime.java:246)
at org.glassfish.jersey.client.JerseyInvocation$1.call(JerseyInvocation.java:667)
at org.glassfish.jersey.client.JerseyInvocation$1.call(JerseyInvocation.java:664)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
at org.glassfish.jersey.internal.Errors.process(Errors.java:228)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:424)
at org.glassfish.jersey.client.JerseyInvocation.invoke(JerseyInvocation.java:664)
at org.glassfish.jersey.client.JerseyInvocation$Builder.method(JerseyInvocation.java:424)
at org.glassfish.jersey.client.JerseyInvocation$Builder.post(JerseyInvocation.java:333)
at com.hive5.rest.api.JerseyClientExamples.sendingInlineImage(JerseyClientExamples.java:152)
at com.hive5.rest.api.JerseyClientExamples.main(JerseyClientExamples.java:88)


And after having looked up on the internet I have not been able unfortunately to figure out why I got this error (any help would be highly appreciate).

So my questions are:

1 - Why do I get this error message?

2 - And what should I do to get rid of this error message and resolving this problem?

Answer

Your pom.xml looks a bit messy you have deps on jersey 2 and 1, you also have duplicate dependencies to handle json on jackson and genson, etc.

You should first clean it and check if you want to use jersey 1 or 2.

For the old version you need jersey-multipart, for the new one it is jersey-media-multipart.

Then register it on the client side

final Client client = ClientBuilder.newBuilder()
  .register(MultiPartFeature.class)
  .build();

And server side

final Application application = new ResourceConfig()
  .register(MultiPartFeature.class)

Documented here.

Note also that you are using com.sun.jersey.multipart.FormDataMultiPart, but in jersey 2 it is org.glassfish.jersey.media.multipart.FormDataMultiPart, again cleaning your dependencies should show you where you are mixing jersey 1 and 2, it is probably the cause.