I am trying to use the mailgun Java API for my kotlin project and want to send emails using templates. I believe I have followed the docs but I am getting a 400 Bad Request response.
My kotlin code looks like:
val client = MailgunClient.config("https://api.eu.mailgun.net/", "<raw-api-key>")
.logLevel(Logger.Level.HEADERS)
.createApi<MailgunMessagesApi>(MailgunMessagesApi::class.java)
val message = Message.builder()
.from("Sender name <sender#domain1.com>")
.to("receiver#domain2.com")
.template("template_name")
.subject("Hello")
.mailgunVariables(
mapOf(Pair("param1": "Hello"), Pair("param2": "world"), Pair("param3": "2020-01-01"))
.build()
client.sendMessageFeignResponse(domain, message)
The response logging I get says:
HTTP/1.1 400 Bad Request
access-control-allow-credentials: true
access-control-allow-origin: *
cache-control: no-store
content-length: 78
content-type: application/json;
date: Thu, 22 Dec 2022 00:54:29 GMT
strict-transport-security:
x-xss-protection: 1; mode=block
{}
feign.Response$ByteArrayBody#1744d3cb
I have tried the following and it works in the command line:
curl -s --user 'api:<raw-api-key>' \
https://api.eu.mailgun.net/v3/<user-domain>/messages \
-F from='Sender name <sender#domain1.com>' \
-F to=receiver#domain2.com \
-F template='template_name' \
-F subject='Hello' \
-F t:variables='{"param1": "Hello", "param2": "world", "param3": "2020-01-01"}'
To be more specific, I mean specifically to just consume the HTTP headers over the network and stop the communication before the client receives the response body.
Example
Client makes a request
GET / HTTP/1.1
Host: example.com
Connection: Keep-Alive
User-Agent: Apache-HttpClient/UNAVAILABLE (Java/1.8.0_262)
Accept-Encoding: gzip,deflate
Then the response over the network is just
HTTP/1.1 200 OK
Date: Wed, 23 Sep 2020 22:41:21 GMT
Server: Apache
Expires: Sun, 19 Nov 1978 05:00:00 GMT
Cache-Control: public, max-age=10800
Content-Language: en
Vary: Cookie,Accept-Encoding
Content-Encoding: gzip
Content-Type: text/html; charset=utf-8
Age: 1865
grace: none
Content-Length: 9213
Connection: keep-alive
Accept-Ranges: bytes
Http protocol has six method, one of the methods is 'HEAD'. You can try use HEAD method instead of GET method.
And another stupid way : declare a web interface, and return null string.Like this:
// a web interface
String result = "";
return result;
I am trying to get contents of the page: http://www.washingtonpost.com/wp-srv/simulation/simulation_test.json
I am able to get the contents in my java project. Here is the code:
HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet(url);
HttpResponse response = client.execute(request);
BufferedReader rd = new BufferedReader(
new InputStreamReader(response.getEntity().getContent()));
StringBuffer result = new StringBuffer();
String line = "";
while ((line = rd.readLine()) != null) {
result.append(line);
}
This prints the contents in my Java project.
However, when I execute this code in my Android project, I get the following in return :
<HTML><HEAD><TITLE>Cisco Systems Inc. Web Authentication Redirect</TITLE><META http-equiv="Cache-control" content="no-cache"><META http-equiv="Pragma" content="no-cache"><META http-equiv="Expires" content="-1"><META http-equiv="refresh" content="1; URL=https://1.1.1.1/login.html?redirect=www.washingtonpost.com/wp-srv/simulation/simulation_test.json"></HEAD></HTML>
How can i solve this problem? why does it occur only in my Android project and not in my Java project?
Thanks
ref for android client
assume not useing proxy when on android connected to WIFI.
Assume that on android you are NOT using net interface for 3G/4G
Assume that you are using the android httpclient packages and not the apache httpclient.
assume that manifest has granted Web permissions.
You have to know the above in order to do much with debug.
You will get a bunch of default headers from default packages when you invoke these:
HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet(url);
You will need to either turn on logging for WIRE & HEADERS OR you will need to dump your headers for the get request so that you know exactly whats in there.
Then , compare your android generated http GET ( all headers ) to the curl test script you see below.. If your android headers are reasonably close ( dont need to be exact there can be some extras in there like 'gzip' encoding ) to the curl headers , then the android will work. The curl example shows only 3 headers and i would make a wild guess that your android client , by default, is setting 7 or 8 headers and that the WP server does not like something in the cruft of the extra headers and is redirecting to the logon.
# ~$ curl --verbose http://www.washingtonpost.com/wp-srv/simulation/simulation_test.json
* About to connect() to www.washingtonpost.com port 80 (#0)
* Trying 23.204.109.48...
* connected
* Connected to www.washingtonpost.com (23.204.109.48) port 80 (#0)
> GET /wp-srv/simulation/simulation_test.json HTTP/1.1
> User-Agent: curl/7.28.1-DEV
> Host: www.washingtonpost.com
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: webserver
< Content-Type: text/plain
< Last-Modified: Wed, 12 Feb 2014 21:16:22 GMT
< Content-Length: 58187
< ETag: "e34b-52fbe4a6"
< Accept-Ranges: bytes
< Date: Mon, 10 Mar 2014 16:54:42 GMT
< Connection: keep-alive
<
{
"posts": [
android httpclient 4.3 sample with HEADER logs turned on...
D/ch.boye.httpclientandroidlib.headers(15360): http-outgoing-2 >> PUT /1/classes/MediaItem/XPdLazBUzV HTTP/1.1
D/ch.boye.httpclientandroidlib.headers(15360): http-outgoing-2 >> Content-Length: 90
D/ch.boye.httpclientandroidlib.headers(15360): http-outgoing-2 >> Content-Type: application/json; charset=UTF-8
D/ch.boye.httpclientandroidlib.headers(15360): http-outgoing-2 >> Host: api.parse.com
D/ch.boye.httpclientandroidlib.headers(15360): http-outgoing-2 >> Connection: Keep-Alive
D/ch.boye.httpclientandroidlib.headers(15360): http-outgoing-2 >> User-Agent: Apache-HttpClient/UNAVAILABLE (java 1.5)
D/ch.boye.httpclientandroidlib.headers(15360): http-outgoing-2 >> Accept-Encoding: gzip,deflate
D/ch.boye.httpclientandroidlib.headers(15360): http-outgoing-2 >> X-Parse-Session-Token: li9ds
D/ch.boye.httpclientandroidlib.headers(15360): http-outgoing-2 >> X-Parse-Application-Id: 3qovv
D/ch.boye.httpclientandroidlib.headers(15360): http-outgoing-2 >> X-Parse-REST-API-Key: Theoj
D/
I have a file online with information about some Minecraft blocks. When I first made this test file, I gave it three rows and a header expiration date of next Sunday (whenever that may be). My Java app fetched this no problem!
However, now I have inserted three more rows into this small database and changed the expiration date to last week, but my Java app still displays the original 3! When I visit the page in a browser, it gives me the full, current table. How come the Java app is still only fetching the old version?
The key code:
InputStream in;
URLConnection urlc = url.openConnection(); // url is a valid java.net.URL object
urlc.setAllowUserInteraction(false);
urlc.setDoInput(true);
urlc.setDoOutput(false);
urlc.setRequestProperty("User-Agent", "BHMI/3.0.0 (+http://prog.BHStudios.org/BHMI) Java/" + System.getProperty("java.version") + "(" + System.getProperty("java.vm.name") + ")"); // GoDaddy blocks Java clients, so we must have a custom user agent string
urlc.setDefaultUseCaches(false);
urlc.setUseCaches(false);
urlc.connect();
System.out.println("Connection successful! Database expires " + new Date(urlc.getExpiration()));
in = urlc.getInputStream();
int data;
StringBuilder sb = new StringBuilder();
while ((data = in.read()) != -1)
sb.append((char) data);
System.out.println("RAW DATA:\r\n"+sb);
Sample output:
Connection successful! Database expires Tue Nov 26 00:09:05 EST 2013
RAW DATA:
minecraft:air,Air,0,0,,
minecraft:stone,Stone,1,0,2,
minecraft:grass,Grass,2,0,,
I cleared the Java network cache through Windows control panel, and all caches and temporary files on my local machine with CCleaner, but this still happens. Heck, it happens across machines, so it can't be that. I've cleared all edge caches from my server, so it also can't be that.
I've even tried downloading the file after telling my browser to use my Java app's User-Agent string, and it fetched all 5 lines.
Request Headers
From my Java app:
GET /http/bhstudios/v2/prog/bhmi/database/get HTTP/1.1
User-Agent: BHMI/3.0.0 (+http://prog.BHStudios.org/BHMI) Java/1.7.0_45(Java HotSpot(TM) 64-Bit Server VM)
Cache-Control: no-cache, must-revalidate, max-age=0, no-store
Pragma: no-cache
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Connection: close
Host: BHStudios.org
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
From Chrome, spoofing the same User-Agent string:
GET /prog/bhmi/database/get/ HTTP/1.1
Host: prog.bhstudios.org
Connection: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
User-Agent: BHMI/3.0.0 (+http://prog.BHStudios.org/BHMI) Java/1.7.0_45(Java HotSpot(TM) 64-Bit Server VM)
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Cookie: __cfduid=dc9d0394ed55ebb1214fcbb5fc825626b1385426208553; visitorId=5293ed2b758cb1b5620000b0
Response Headers
From my Java app:
HTTP/1.1 200 OK
Server: cloudflare-nginx
Date: Tue, 26 Nov 2013 02:17:39 GMT
Content-Type: text/html
Transfer-Encoding: chunked
Connection: keep-alive
Set-Cookie: __cfduid=d4432e3d81cf9e5b9393f2cca483e4b2d1385432256651; expires=Mon, 23-Dec-2019 23:50:00 GMT; path=/; domain=.bhstudios.org; HttpOnly
X-Powered-By: ASP.NET
X-UA-Compatible: chrome=IE8
CF-RAY: d33155416660862
Note that suspicious cookie expiration expires=Mon, 23-Dec-2019 23:50:00 GMT. Could this be the cause?
I also note that, when fetching from Chrome and using the same User-Agent string as my app, the header is:
HTTP/1.1 200 OK
Server: cloudflare-nginx
Date: Wed, 27 Nov 2013 17:30:01 GMT
Content-Type: text/html
Transfer-Encoding: chunked
Connection: keep-alive
Cache-Control: no-cache, must-revalidate, max-age=0, no-store
Pragma: no-cache
Expires: Mon, 18 Nov 2013 10:30:01 America/Phoenix
Content-Description: File Transfer
Content-Disposition: attachment; filename=BHMI_Items_Vanilla_172.csv
Content-Transfer-Encoding: base64
X-Powered-By: ASP.NET
X-UA-Compatible: chrome=IE8
CF-RAY: d408b3c56320098
Content-Encoding: gzip
which is the intended header, with an expiration date of last week.
You have to put in your request header info that you are looking for data that are not cached:
urlc.setRequestProperty("Cache-Control","no-cache, must-revalidate"); //HTTP 1.1
urlc.setRequestProperty("Pragma","no-cache"); //HTTP 1.0
... I was requesting the wrong file.
Sorry for wasting your time >.<
As the header shows, I was addressing an old URL scheme, /http/bhstudios/v2/prog/bhmi/database/get, when I wanted /prog/bhmi/database/get
I'm trying to send a request, I do the following in curl:
curl -v --header "location: 60.004:8.456" --cookie "sessionToken=~session" -i -X PUT -H 'Content-Type: application/json' -d '{"data":"{"FCT":"Welcome", "Uni":"Welcome to DI"}"}' localhost:8080/tester/apps/e39/data
and for some reason it matches the class but no this method:
#PUT
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response createDocumentRoot(JSONObject inputJsonObj,
#Context UriInfo ui, #Context HttpHeaders hh) {
}
Edit:
The class is defined with #Path("{appId}/data")
The problem isn't the paths, as I've debugged it and seen it identifies the class right, it just throws the bad request after going inside the class without entering any method.
Here is the curl verbose:
* About to connect() to localhost port 8080 (#0)
* Trying 127.0.0.1... connected
> PUT /tester/apps/e39/data HTTP/1.1
> User-Agent: curl/7.22.0 (i686-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3
> Host: localhost:8080
> Accept: */*
> Cookie: sessionToken=~session
> location: 60.004:8.456
> Content-Type: application/json
> Content-Length: 60
>
* upload completely sent off: 60out of 60 bytes
< HTTP/1.1 400 Bad Request
HTTP/1.1 400 Bad Request
< Server: Apache-Coyote/1.1
Server: Apache-Coyote/1.1
< Content-Type: text/html;charset=utf-8
Content-Type: text/html;charset=utf-8
< Content-Length: 990
Content-Length: 990
< Date: Tue, 02 Jul 2013 21:46:56 GMT
Date: Tue, 02 Jul 2013 21:46:56 GMT
< Connection: close
Connection: close
The problem was in the json syntax that was incorrect, I had
'{"data":"{"FCT":"Welcome", "Uni":"Welcome to DI"}"}'
after changing to this, it worked fine:
'{"data":
{"FCT":"Welcome",
"Uni":"Welcome to DI"}}'
I used a JSON online parser to check the json syntax, here is the link incase someone needs it:
http://json.parser.online.fr/