Unable to send mail via Mailgun over api or smtp - mailgun

I have setup a new account and not verified my domain. I would like to test and confirm mail-send before proceeding with verification and adding payment information.
I have tried curl using the sandbox method and api key (including smtp). I have also tried to use my domain using the top account mail-address as recipient. But each time the send command (both curl and smtp) I get "Mailgun Magnificent API" response - but no mail is delivered. So far the Mailgun API does not look so Magnificent... I have gone through the documentation multiple times and cannot find what I might be doing wrong..
Any help is much appreciated.

Faced the same issue while sending emails via api by php curl. I solved it by changing API Base URL https://api.mailgun.net/v3/YOUR_DOMAIN_NAME to https://api.mailgun.net/v3/YOUR_DOMAIN_NAME/messages.
It's because their api is not only for sending.
Hope this helps.

For anyone else trying to figure out what "Mailgun Magnificent API" means in a Mailgun HTTP 200-OK API response, it occurs when posting to https://api.mailgun.net/v3/YOUR_DOMAIN_NAME/some/api/endpoint when /some/api/endpoint is not a valid Mailgun API endpoint.
If you are using a client library, there's probably a mistake in your Mailgun sender domain setting. Say you've verified the domain mg.example.com with Mailgun. Examples that can result in "Mailgun Magnificent API" (the exact setting name depends on the library):
MAILGUN_DOMAIN = mg.example.com # comment—this is a common mistake in dotenv files, which don't usually support inline comments; move the # comment to its own line
MAILGUN_DOMAIN = mg.example.com/mysite—get rid of the /mysite part
If you are posting directly to the Mailgun API (or developing a client library), there are some additional ways you might get "Mailgun Magnificent API":
Omitting the API endpoint: https://api.mailgun.net/v3/mg.example.com (as noted in another response)
Misspelling the endpoint: https://api.mailgun.net/v3/mg.example.com/massages (that should be messages with an e)
Including a # or ? after your domain: https://api.mailgun.net/v3/mg.example.com #/messages (see the note above about comments in config files)
Including an extra path after your domain: https://api.mailgun.net/v3/mg.example.com/route/to/my/app/messages
Note that you won't see "Mailgun Magnificent API" if YOUR_DOMAIN_NAME is not a valid sending domain you've registered with Mailgun. (In that case, Mailgun instead responds 404-Not Found).

The mailgun guide shows you to use https://api.mailgun.net/v3/YOUR_DOMAIN as YOUR_DOMAIN_NAME as in the snippet below and this was the problem.
If you're using mailgun-js, you simply need to have YOUR_DOMAIN as YOUR_DOMAIN_NAME.
No need for the https://api.mailgun.net/v3 part
const API_KEY = 'YOUR_API_KEY';
const DOMAIN = 'YOUR_DOMAIN_NAME';
const mailgun = require('mailgun-js')({apiKey: API_KEY, domain: DOMAIN});
const data = {
from: 'Excited User <me#samples.mailgun.org>',
to: 'foo#example.com, bar#example.com',
subject: 'Hello',
text: 'Testing some Mailgun awesomeness!'
};
mailgun.messages().send(data, (error, body) => {
console.log(body);
});

The problem for me was not including my domain name in the url and trying to type everything onto a single line. Strictly following their online example. Typing a backslash will bring your cursor to a new line.
$ curl -s --user 'api:key-xxx' \
https://api.mailgun.net/v3/your_domain/messages \
-F from='User <user#sample.mailgun.org>' \
-F to='xxx#gmail.com' \
-F subject='Hello' \
-F text='Testing some mailgun!'
Response
{
"id": "<xxx.x.xxx#your_domain>",
"message": "Queued. Thank you."
}

Including an slash "/" after messages url part at the end causes this failure too.
For example if you are using a library like Refit for c#, ensure your service interface be declared like this (see the Post attribute):
public interface IMailgunService
{
[Post("")]
Task<JsonDocument> SendEmailAsync([Body(BodySerializationMethod.UrlEncoded)] Dictionary<string, object> data);
}

Related

How to use Mailgun sandbox?

I am currently testing Mailgun. Therefore, I don't want to add any payment information at the moment.
So, I'm working with the sandbox, and a verified address in the authorized recipients attached to the sandbox. So far, following the documentation, this limited setup is supposed to be working for testing purpose.
I use Postman to better identify how to work with the API, excluding any potential issues with coding.
Here is my Hello World config:
POST https://api:____my_API_Key___#api.mailgun.net/v3/sandboxXXXXX.mailgun.org/messages
The dashboard indicates that the sandbox is located in the US, so I don't use the european API.
Body:
from: postmaster#sandboxXXX.mailgun.org (also tried the verified email address, and postmaster <postmaster#sandbox...>)
to: bob#marley.com (the verified email address)
subject: test
text: Hello World!
I get a 400 error, Bad Request, and the documentation suggests to look for missing parameters.
The other posts I found so far did not help me to find the error spot either.
Also, Mailgun provides a Postman collection. But it did not help either.
Indeed, I dream of a detailed information of the API requirements, value formating... What are the required parameters if the error means I miss some?
Any idea of what I am missing?
Here is the solution.
I had to guess and analyze some examples from the provided Postman Collection to find out what the documentation is supposed to explain in the first place:
4 Required headers:
Authorization
Value : Basic XXXXX, where XXXXX is the Base 64 encoded version of api:___your_API_key___.
Content-Type
Value : multipart/form-data; boundary=XXX, where XXX is any short single string that will be used to identify a boundary within the sent content.
Content-Length
Value : XXX, where XXX is the size of the body request.
Host
Value : mydomain.com, your IP if sending from Postman...

HTTP request header is removed in Google cloud run

When I try to send a HTTP post request from my UI to the Google cloud run hosted backend, the header named x-google-token is automatically removed. Tried with CURL as well. Another header named x-fb-token is working fine though. Could someone please explain what's happening?
I came across this article which explains the problem. As it turns out, Google cloud run removes headers with names that match the X-Google-* pattern from incoming requests because those patterns are reserved for Google.
The following headers are removed from incoming requests if a client
sends them:
Headers with names that match the X-Google-* pattern. This name
pattern is reserved for Google.
Here is the full article:
https://cloud.google.com/appengine/docs/standard/go/reference/request-response-headers

Can AWS API Gateway support `application/x-www-form-urlencoded` with body and query string parameters?

Numerous services can accept query string parameters in the URL when a POST request is made with Content-Type: application/x-www-form-urlencoded and other parameters in the body, but it seems AWS API Gateway cannot while also accepting query string parameters.
When I call the AWS API Gateway with a POST Mapping Template for application/x-www-form-urlencoded and query string URL parameters (with a Lambda function), I get the following error:
{
"message":"When Content-Type:application/x-www-form-urlencoded,
URL cannot include query-string parameters (after '?'):
'/prod/webhook?inputType=wootric&outputType=glip&url=...'"
}
Here is an example cURL:
curl -XPOST 'https://{myid}.execute-api.{myregion}.amazonaws.com/prod/webhook? \
inputType=wootric&outputType=glip&url=https://hooks.glip.com/webhook/ \
11112222-3333-4444-5555-666677778888' \
-d "#docs/handlers/wootric/event-example_response-created.txt" \
-H 'Content-Type: application/x-www-form-urlencoded' -v
The specific goal is to get a Wootric webhook event posted to a Lambda function using a URL with query string parameters.
You can get the code here:
https://github.com/grokify/chathooks
The Wootric event body file is here:
https://raw.githubusercontent.com/grokify/chathooks/master/docs/handlers/wootric/event-example_response-created.txt
The GitHub issue is here:
https://github.com/grokify/chathooks/issues/15
The error message seems pretty definitive but I wanted to ask:
Is there a workaround to configure an API Gateway to support both?
Is there a standards-based reason why AWS would not support this or is this just a design decision / limitation?
If there's no solution to this, is there a good lightweight solution other than deploying a hosted server solution like Heroku. Also, do other cloud services support this with their API gateway + cloud functions, like Google?
Some examples showing support for both:
jQuery example: jQuery send GET and POST parameters simultaneously at AJAX request
C# example: Accessing query string variables sent as POST in HttpActionContext
Yes,there is a workaround and the key issue is to set the mapping template that will convert string into json . Very detailed example shown in
API Gateway any content type.
Please set the request property as "Content-Type", "application/json" for your HttpURLConnection like below
connection.setRequestProperty("Content-Type", "application/json");
I had a similar problem, with a 3rd party provider using web hooks. It turns out that my provider is transforming the url path from UPPERCASE to LOWERCASE. Example the endpoint should be apigateway.com/dev/0bscur3dpathRANDOM instead apigateway.com/dev/0bscur3dpathRANDOM. You get the point.
I'm not sure if I got the point in question correctly, but if you want to access the request body that is encoded as application/x-www-form-urlencoded(or anything, actually) in your Lambda function, you should use LAMBDA_PROXY request integration type (aka tick "Use Lambda Proxy integration" checkbox) when creating a method for your resource. Then you can access the request body in event.body field as a plain text in your lambda function and parse it manually.

Vapor Client with Authentication

I need to auth on the server that I'm trying to pull data from I currently have it connecting to the server with:
let urlString = "\(makeUrl(grammar: grammar))&\(query)"
let drop = Droplet()
return try drop.client.get(urlString)
But I can't seem to figure out how to get creds attached to the get request. I tried just putting the user and password into the url but found the vapor client doesn't allow that:
/*
Userinfo (i.e., username and password) are now disallowed in HTTP and
HTTPS URIs, because of security issues related to their transmission
on the wire. (Section 2.7.1)
*/
With a little nudge from the Vapor Slack channel and a little code diving in the AlamoFire repo I have found the solution.
First you need to base64 encode the username name and password and then add it to the http header.
func performRequest(query: String, grammar: FMPGrammar) throws -> Response {
let urlString = "\(makeUrl(grammar: grammar))?\(query)"
let loginString = "\(userName):\(password)"
let b64Login = Data(loginString.utf8).base64EncodedString(options: [])
let drop = Droplet()
let result = try drop.client.get(urlString, headers: [.authorization : "Basic \(b64Login)"])
return result
}
Like the error states, it is a HUGE security risk to include username/password credentials in plaintext as GET uri parameters. You should (at a minimum) be sending them in a POST call.
Check out the blog post on User Authentication with Vapor to see a pretty decent example of setting up user authentication with Vapor. The blog is a little old now (Vapor has changed a lot since then), but I think pretty much everything in it should still work. At least conceptually.
Also, you join the Vapor Slack channel and ask questions in there :)
qutheory.slack.com

Bad request error with ruby google-api-client when querying Google Admin Directory API

I am using version 0.6.4 of google-api-client ruby gem to query Google Admin Directory API.
Here is my session in ruby console:
require 'rubygems'
require 'google/api_client'
SERVICE_ACCOUNT_CLIENT_ID = "SOME_STRING.apps.googleusercontent.com"
SERVICE_ACCOUNT_EMAIL = "SOME_STRING#developer.gserviceaccount.com"
SERVICE_ACCOUNT_PKCS12_FILE_PATH = "/path/to/privatekey.p12"
key = Google::APIClient::KeyUtils.load_from_pkcs12(SERVICE_ACCOUNT_PKCS12_FILE_PATH, 'notasecret')
asserter = Google::APIClient::JWTAsserter.new(SERVICE_ACCOUNT_EMAIL, "https://www.googleapis.com/auth/admin.directory.device.chromeos.readonly", key)
client = Google::APIClient.new
client.authorization = asserter.authorize
dir_api = client.discovered_api('admin', 'directory_v1')
resp = client.execute(:api_method => dir_api.chromeosdevices.list, :parameters => {'customerId'=>SERVICE_ACCOUNT_CLIENT_ID})
resp.body
=> "{\n \"error\": {\n \"errors\": [\n {\n \"domain\": \"global\",\n \"reason\": \"badRequest\",\n \"message\": \"Bad Request\"\n }\n ],\n \"code\": 400,\n \"message\": \"Bad Request\"\n }\n}\n"
I am probably missing something obvious here but it is unclear from the error response what is missing in the request. Would appreciate any help/pointers in the right direction.
Thanks.
I got a similar response in my C# program, listing users in my domain.
I still haven't resolved it but so far I managed to get the same error message in
The APIs Explorer https://developers.google.com/apis-explorer/#p/admin/directory_v1/
when trying to do the same request there and omitting any value for domain.
That led me to believe that I somehow needed to add the domain to my request in my C#-code and by trial and error I THINK I found how to do it in C#.
But my suggestion is to try your API request in the APIs Explorer and then se if you could get the same error message there by NOT submitting the value for domain, as I think that's what the error-message means.
I've had the same problems. I've wrote an example gist which explains how to set it up:
https://gist.github.com/thomaswitt/7468182
Steps are:
Go to Google Cloud Console (https://cloud.google.com/console)
Create Service Account with P12 File
Enable the Admin SDK in APIs.
Create a Project
Create a registered app within this project
Go to section 'Certificate' and generate a key
Download the JSON file as well
Go to the Apps Console > Security > Extended > 3rdPartgy OAuth
(https://admin.google.com/AdminHome?#OGX:ManageOauthClients)
Add an API Client. Client name is value of client_id in the JSON
file, API Scope is https://www.googleapis.com/auth/admin.directory.user.readonly
I found that #JoBe's answer was pretty much on track. In Ruby, using the Google-Api-Client gem, you need to pass a hash to list_users, with the domain. i.e.
UserService.list_users(domain: 'mydomain.com').