[SOLVED] PHP curl 401 and 405 errors

One for the weekend workers :slight_smile:

I am attempting to make use of the MIAB API from our external server. (our MAIB is on a separate dedicated server)

Our external server uses PHP7 in entirety.

Attempting PHP curl to get a user list:
using ‘GET’ results in a 401
using ‘POST’ results in a 405 (obviously from a security perspective I’d rather use POST)

  1. Has anyone done this and managed to get it to work?

2 just how extensive is the MIAB API? (list/add/delete/ … send/read/delete should be achievable through POP … anything else?



  1. Has anyone done this and managed to get it to work?

No, I have no PHP background

  1. just how extensive is the MIAB API? (list/add/delete/ … send/read/delete should be achievable through POP … anything else?

It supports only e-mail accounts and DNS changes as far as I know.

Have you tried the API from your remote server on the eterminal with curl, does it work? If not What about from terminal curl on the MIAB itself?


Yes so with PHP CURL POST or GET is irrelevant for security as everything should be done over SSL.

Here are 2 of my projects that use the MIAB cURL API, please see if you can copy the code and get yours to work:

DNS Management: https://github.com/mitchellurgero/mailinabox_dynamic_dns_script

Email Registration / Management: https://github.com/mitchellurgero/miab_registration_script

They are not perfect, and are a little sloppy, but the code works as of version 0.26b and as far back as version 0.19

Saw that one yesterday and will have a better look at it tomorrow.
Remember this will be running on a different machine (not the MAIB) but one running PHP+Apache+NodeJS.

I think, my problem is converting the curl commands to PHP curl as they work ok from within the MIAB.
I’ll be back to it later in the week - have other balls to juggle today :frowning:

My registration script uses CURL API - and can also be ran from a different server other than MIAB.

Change line 151 to match your server needs:
$return = shell_exec('curl -X POST -k --insecure --user '.$config['m'].':'.$config['p'].' -d "email='.$username.'@'.$config['domain'].'" -d "password='.$password.'" https://example.com/admin/mail/users/add');

(see the change above for an example.)

1 Like

As for PHP’s cURL functions:
$url = "https://box.example.com/admin/"; $domain = "example.com" $handle = curl_init($url."$domain"); curl_setopt($handle, CURLOPT_RETURNTRANSFER, true); curl_setopt($handle, CURLOPT_CUSTOMREQUEST, "DELETE"); curl_setopt($handle, CURLOPT_USERPWD, "$username:$password"); curl_setopt($handle, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); curl_setopt($handle, CURLOPT_TIMEOUT, 10); $ret = curl_exec($handle); curl_close($handle); if(strpos($ret,"updated DNS") !== false){ return "SUCCESS"; } else { return "ERROR: $ret"; } return $ret;

Replace “DELETE” with either PUT, GET, or POST as needed.

Although not a perfect tool, this definitely helped: https://incarnate.github.io/curl-to-php/ (It’s a CURL CLI to PHP CURL converter.)

1 Like

That was excellent advice and pointed me in a direction to a solution.

It turns out the the 405 error is indicating some error in the parameters.
Apparently in my case the new user password was only 7 characters not 8, simple mistake but a lot of grief. would have been nice to get the same verbose error message from curl’ing within terminal.

The other big problem was I had forgotten to set up the curl SSL certificate correctly on the local server. Hence the 401 errors.

My php routine just for completeness and anyone else passing by:

 echo CallMAIB_API('GET', 'users');
 // or echo CallMAIB_API('POST', 'users/add', "email=new_user@anonemail.email&password=passwordofatleast8chars");
 // or echo CallMAIB_API('POST', 'users/remove', "email=new_user@anonemail.email");
 // Note: MAIL_URL = https://example.com/mail/admin/mail/  MAIL_USER = an admin user MAIL_KEY = admin user's password
 function CallMAIB_API($method='POST', $path='', $postdata='', $headers=array()) {
	$qs = (!empty($postdata) && 'GET' === $method) ? '?' . ltrim($postdata, '?') : '';
 	$ch = curl_init();

	curl_setopt($ch, CURLOPT_URL, MAIL_URL . $path . $qs);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
	curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);

	curl_setopt($ch, CURLOPT_USERPWD, MAIL_USER . ":" . MAIL_KEY);

	if (!empty($postdata) && in_array($method, array('POST', 'PUT'))) {
		curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata);

	$headers[] = "Content-Type: application/x-www-form-urlencoded";
	curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
	curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.2309.372 Safari/537.36');

	// we don't want any HTTPS errors so a certificate should be installed from: http://curl.haxx.se/docs/caextract.html (and regularly updated)
	// placed in the \php\ directory and the php.ini file updated in the [curl] options with "curl.cainfo=c:\php\cacert.pem"
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
	curl_setopt($ch, CURLOPT_TIMEOUT, 10);

	$response = curl_exec($ch);

	// check the HTTP Status code
	$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
	if (200 !== $httpCode) {
		$response = "$httpCode: ";
		switch ($httpCode) {
			case 200: break;
			case 404:
				$response .= "Mail API Not found";
			case 401:
			case 405:
				$response .= "Mail API Error: Check Authentication (password length > 8?) and SSL certificate";
			case 500:
				$response .= "Our servers replied with an error.";
			case 502:
				$response .= "Our servers may be down or being upgraded. Hopefully they will be OK soon!";
			case 503:
				$response .= "Mail service ; unavailable. Hopefully it will be OK soon!";
				$response = 'Undocumented error: ' . $httpCode . ' : ' . curl_error($ch);
	return $response;

Yea so HTTP 4XX status codes (404, 401, 403, 405) are client side errors that are reported by the server:

401: Unauthorized (Bad Password 9/10 times)
403: Forbidden (Permissions issues)
404: File (or folder) not found. (Because the client requested a non-existing file)
405: Method Not Allowed. (Using GET when POST is supposed to be used as an example)

Keep these in mind as you troubleshoot friend, cheers!

Sources: https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#4xx_Client_errors

1 Like