Swift: Mailgun 401 response code--No valid API key provided - swift

So I have my send email function as seen below:
func email() {
let session = URLSession.shared
let request = NSMutableURLRequest(url: NSURL(string: "https://api.mailgun.net/v3/sandbox################################/messages")! as URL)
request.httpMethod = "POST"
let credentials = "api:key-################################-########-########"
request.setValue("Basic \(credentials.toBase64())", forHTTPHeaderField: "Authorization")
let data = "from: Swift Email <(test#test.com)>&to: [myemail#gmail.com,(myemail#gmail.com)]&subject:Hello&text:Testing_some_Mailgun_awesomness"
request.httpBody = data.data(using: String.Encoding.ascii)
let task = session.dataTask(with: request as URLRequest, completionHandler: {(data, response, error) in
if let error = error {
print(error)
}
if let response = response {
print("url = \(response.url!)")
print("response = \(response)")
let httpResponse = response as! HTTPURLResponse
print("response code = \(httpResponse.statusCode)")
}
})
task.resume()
}
So I guess either my API key is wrong or my request URL is wrong. To find my request URL, I went to https://app.mailgun.com/app/dashboard and then scrolled down to the Sending Domains section and copied that. To get my API key I went to https://app.mailgun.com/app/account/security/api_keys and just copied the Private API Key. I'm really not sure why I'm getting this invalid code--thank you in advance if you figure it out!
Side note: Not really sure if the data constant is set up right (in terms of missing or having too many parens), so if you could check that too that would be phenomenal.

I have a software called "paw" it helps forming REST API call for Xcode, curl, php, etc.
I don't know if this could help you
class MyRequestController {
func sendRequest(somevar: String, completion: #escaping (Books) -> Void) {
/* Configure session, choose between:
* defaultSessionConfiguration
* ephemeralSessionConfiguration
* backgroundSessionConfigurationWithIdentifier:
And set session-wide properties, such as: HTTPAdditionalHeaders,
HTTPCookieAcceptPolicy, requestCachePolicy or timeoutIntervalForRequest.
*/
let sessionConfig = URLSessionConfiguration.default
/* Create session, and optionally set a URLSessionDelegate. */
let session = URLSession(configuration: sessionConfig, delegate: nil, delegateQueue: nil)
/* Create the Request:
(POST https://api.mailgun.net/v3/YOUR_DOMAIN_NAME/messages)
*/
guard var URL = URL(string: "https://api.mailgun.net/v3/YOUR_DOMAIN_NAME/messages") else {return}
var request = URLRequest(url: URL)
request.httpMethod = "POST"
// Headers
request.addValue("Basic YXBpOllPVVJfQVBJX0tFWQ==", forHTTPHeaderField: "Authorization")
request.addValue("multipart/form-data; charset=utf-8; boundary=__X_PAW_BOUNDARY__", forHTTPHeaderField: "Content-Type")
// Body
let bodyString = "--__X_PAW_BOUNDARY__\r\nContent-Disposition: form-data; name=\"from\"\r\n\r\n'Excited User <mailgun#YOUR_DOMAIN_NAME>'\r\n--__X_PAW_BOUNDARY__\r\nContent-Disposition: form-data; name=\"to\"\r\n\r\nYOU#YOUR_DOMAIN_NAME\r\n--__X_PAW_BOUNDARY__\r\nContent-Disposition: form-data; name=\"to\"\r\n\r\nbar#example.com\r\n--__X_PAW_BOUNDARY__\r\nContent-Disposition: form-data; name=\"subject\"\r\n\r\n'Hello'\r\n--__X_PAW_BOUNDARY__\r\nContent-Disposition: form-data; name=\"text\"\r\n\r\n'Testing some Mailgun awesomeness!'\r\n--__X_PAW_BOUNDARY__--\r\n"
request.httpBody = bodyString.data(using: .utf8, allowLossyConversion: true)
/* Start a new Task */
let task = session.dataTask(with: request, completionHandler: { (data: Data?, response: URLResponse?, error: Error?) -> Void in
if (error == nil) {
// Success
let statusCode = (response as! HTTPURLResponse).statusCode
print("URL Session Task Succeeded: HTTP \(statusCode)")
}
else {
// Failure
print("URL Session Task Failed: %#", error!.localizedDescription);
}
})
task.resume()
session.finishTasksAndInvalidate()
}
}
**** and you CALL this function a bit like this
MyRequestController().sendRequest(somevar: "something")
take a look at https://www.youtube.com/watch?v=44APgBnapag for more details
this tutorial show how to do REST API calls with Xcode, this example it scan a barcode, send the scanned code via a function that calls the API and return infos...

Related

Using Swift with URLSession works with GET and PUT, but it gives error 405 Method Not Allowed when I use POST

I develop an iOS app using Swift.
I use the following method below to access an login ENDPOINT with PUT method.
let loginData = LoginModel("myUser","myPassword")
var loginClassJson:Data?
do{
loginClassJson = try JSONEncoder().encode(loginData)
} catch {
fatalError("Unable To Convert in Json")
}
let completeUrl = URL(string: RESconstantes.URL_PRINCIPAL_TREINAGEDAVE + "/login" )!
var request = URLRequest(url: completeUrl)
let myConfig = URLSessionConfiguration.default
let base64LoginString = EndpointController.getBase64StringLoginWithUserAndPasswordV2()
myConfig.httpAdditionalHeaders = ["Authorization" : base64LoginString]
request.httpMethod = "PUT"
request.setValue("\(String(describing: loginClassJson!.count))", forHTTPHeaderField: "Content-Length")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = loginClassJson
let sessionDelegate = SessionDelegate()
let urlSession = URLSession(configuration: myConfig, delegate: sessionDelegate, delegateQueue: OperationQueue.main)
let task = urlSession.dataTask(with: request as URLRequest, completionHandler: {
(data, response, error) in
if let error = error{
print("errorX: ")
print(error)
return
}
if let data = data{
let returnData = String(data: data, encoding: String.Encoding.ascii)
print("dataX: ")
print(returnData)
}
if let response = response{
print("responseX: ")
print(response)
}
})
task.resume()
print("END")
This is my URLSessionDelegate class
class SessionDelegate:NSObject, URLSessionDelegate
{
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: #escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
// usado para fazer o bypass na autenticaĆ§Ć£o self-signed do certificado do servidor
// We've got a URLAuthenticationChallenge - we simply trust the HTTPS server and we proceed
print("start didReceive challenge 1")
if true {
print("didReceive challenge 2")
completionHandler(.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!))
}else{
completionHandler(.performDefaultHandling, nil)
}
}
It works perfectly for me, but now I try to create a code to access another ENDPOINT with POST method
let resDadoModel = ResDadoModel.getResenhaById(1)
let jsonRequestUploadResenha = ResDadoModel.createMockJsonObjectResenhaDados(resDadoModel)
let json: [String: Any] = jsonRequestUploadResenha
guard let jsonData:Data = try? JSONSerialization.data(withJSONObject: json) else {
print("guard jsonData error")
return
}
let completeUrl = URL(string: RESconstantes.URL_PRINCIPAL_TREINAGEDAVE + "/validaResenha" )!
var request = URLRequest(url: completeUrl)
let myConfig = URLSessionConfiguration.default
let base64LoginString = EndpointController.getBase64StringLoginWithUserAndPasswordV2()
myConfig.httpAdditionalHeaders = ["Authorization" : base64LoginString, "Content-Type":""]
request.httpMethod = "POST"
request.setValue("\(String(describing: jsonData.count))", forHTTPHeaderField: "Content-Length")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = jsonData
let sessionDelegate = SessionDelegate()
let urlSession = URLSession(configuration: myConfig, delegate: sessionDelegate, delegateQueue: OperationQueue.main)
let task = urlSession.dataTask(with: request as URLRequest, completionHandler: {
(data, response, error) in
if let error = error{
print("errorX: ")
print(error)
return
}
if let data = data{
let returnData = String(data: data, encoding: String.Encoding.ascii)
print("dataX: ")
print(returnData)
}
if let response = response{
print("responseX: ")
print(response)
}
})
task.resume()
print("END")
But the code that I use to access the ENDPOINT called "validaResenha" is not working properly, I get a 405 method not allowed error.
I get the following response data
<NSHTTPURLResponse: 0x600002028560> { URL: https://my_url_endpoint/api/spservicos/v1/validaResenha } { Status Code: 405, Headers {
Allow = (
"POST, OPTIONS"
);
"Cache-Control" = (
"no-cache=\"set-cookie, set-cookie2\""
);
Connection = (
"Keep-Alive"
);
"Content-Language" = (
"en-US"
);
"Content-Length" = (
0
);
"Content-Type" = (
"text/plain"
);
Date = (
"Thu, 23 Dec 2021 23:16:21 GMT"
);
Expires = (
"Thu, 01 Dec 1994 16:00:00 GMT"
);
"Keep-Alive" = (
"timeout=10, max=100"
);
"Set-Cookie" = (
"LtpaToken2=L6DEf/sqCSjiI1rePW3wEWZo40oNAsxmNVBNTpIRm3FZZRSSgaqmUTDYdjTq2PNE4+FhiIOKw7Xzuta4+LpD3cUB8QKZQ/KVom/rFFQ50XNkpQezmgMlgsmDDgtodRxVU5eyo1P1NP6r/3M55eY4HkeD583kXQB3/+EH3dIryo0ii6Jn6PrxaspX5noEo0eSt+yF2AylLdU66fCcSMJw7LCrB8Tulna4xHe4Nb9i+O5z2mnTXoIgbozDGuXfS6Y20zPrsaN62Bx1X/nySf1luf1QMhrt6P4SPF6GVudm0s/Db9dS0b444kJA4kMSJ0NbZ2khMzV1zSg3eZY6xZg2kidV8Qczpe5bL2/DNrPQY/CrUo8wcdFE1ebfxDcVrjv3G+nH6uKOPWtbcHHx9Wp1gvHLxj3cJ5MP43AzxW/7GXPA7QlsmlquxW1Ck7OypsP2hrYCvCWubjGdM51cg8uqhIonI+uXRO6BlcXIsPOfpR+LbQfDNo+9vzXzB+CZKZmYnBX63ffWhX09Cr+Ua0a2Sw8mOcE5jXImlO49+ak0FHPkiiaSABzuOl6ALYg9J6LCxjm6MC9bKd7KbMPueJI/ugVeMyphQwss5AHxic8fVmo+7/XNRT6zr4I/01N8xFQsqrvx5+i2AhxWO1bdDKmpZQLPoTHMD7TPcFBkwDXLVqXPXkpkcGvg3mI8ssKOOlxwJT7/SETcqrCY5O8Yr505qdeZiNIj4kjKiLoLuNpE+ZI=; Path=/"
);
} }
Anyone has an idea why I was receiving a 405 error method not allowed? The POST method works for me if I use POSTMAN. It works if I use PUT or GET endpoints with Swift code, but it fails if I try to use endpoints with POST method in Swift.
I see something strange, the "Content-Type" is defined as text/plain in the response, but I set it as "application/json". I don't understand why the config was not being set.
If I call it via POSTMAN, it works, but for some reason I don't know why it not works when I use Swift.
--- EDIT ---
After #matt suggestion, I use Postman to generate the Swift code.
I copy and paste the Swift code to my project, this is the code:
var semaphore = DispatchSemaphore (value: 0)
let parameters = "{ \n \"token\":\"MY_TOKEN\",\n \"resenha\": {\n \"codAP\":\"353750303020001\",\n \"codPropriedade\":\"0\",\n \"cpfVeterinario\":\"01787568814\",\n \"coordGeoLat\": \"37.421565\",\n \"coordGeoLong\": \"-122.084\",\n \"cpfCnpjProdutor\": \"89058500810\",\n \"dataNascimentoAnimal\": \"01/08/1981\",\n \"fotos\": null,\n \"graficas\": null,\n \"id\": \"1\",\n \"idComposicaoPelagem\": \"50\",\n \"idCorOlhoDir\": \"39902\",\n \"idCorOlhoEsq\": \"39902\",\n \"idEspecie\": \"5\",\n \"idPelagem\": \"6\",\n \"idRaca\": \"34\",\n \"idResenhaAnterior\":\"0\",\n \"idSexo\": \"2501\",\n \"machoCastrado\": \"N\",\n \"microChipAnimal\": \"123456989012377\",\n \"microchipMae\": \"\",\n \"nomeAnimal\": \"MACADANIAS111\",\n \"numeroAssocRaca\": \"\",\n \"numeroPassaporte\": \"\",\n \"outrasCaracteristicas\": null,\n \"quantAnimaisEq\": \"05\",\n \"quantAnimaisAs\": \"0\",\n \"quantAnimaisMu\": \"02\",\n \"retifica\": false\n }\n}"
let postData = parameters.data(using: .utf8)
var request = URLRequest(url: URL(string: "https://MY_ENDPOINT/validaResenha")!,timeoutInterval: Double.infinity)
request.addValue("Basic THIS_IS_BASIC_AUTH_VALIDATION", forHTTPHeaderField: "Authorization")
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("JSESSIONID=0000_B1PZRSVcyzEkDUkMxvk9ig:18jgnbg8n; LtpaToken2=q9JsIHVBKPsCYKGRohXJAKnXED3HRXXGlaswzYpnPSLS0B+c/WbiW+QcUMwmw/8xcb7VL1bVvbUh0ZAvMR3TNcGudWUkg9f0z5K0n0P2pJ5Frte6trqVLhPoKuI5E7zwC3Yg+XCsPBNFy0aukkrWNiCWAqbyGI3nir6UuX5qLER4H+bEYfk4cFw58eHGSIN/FTVjH7WW7aEAfkYNXxWzSDnNVJDtihZVXw+oJSfe74Vz8Scv33cPPZH2W74KvKwj09FOo+EJsvFcC2aDUQclYqwuo91HIaIpqcYb17cSCX95xn9KHErlC48M1bU03txKaDVcmUrOCrveCs7pVPNCz066cil5bzjXeYlXDlmUw5MT45Zgg8EmaJ9gi+iC2zPCU+W088OGEriphXpto40ww3irTN9rtnhIppB5U+drRFW6u25UmDkAjx899TNzC/XsJqkRXn9GinQv6xiD+Axnv3AgudQZBGyeYcNNJDRfA+jzbr6HE1NuNSkxY6aP1OvCLGkNDSA16chO7f4IjjR9jkvDH2m3+ajxa7as1rVNK9R0HHcZJLExvOJn3sJ1LKDwMNPTDjKGPLuWOVwTPQL2pzIitLjkeyx8A2Qcqo5p8U/+aa11Z/x8WA0bQRscZLWMtEHE6WLnHFqBaylCAzARF0Y5cOI/TYCW2xd99ux2WaJnumVlskr2uNCWdwSMOp78gvmzdmonQUH0Ko/k4wa8HcJPyMV5NK52gArIyGmeKXo=", forHTTPHeaderField: "Cookie")
request.httpMethod = "POST"
request.httpBody = postData
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data else {
print(String(describing: error))
semaphore.signal()
return
}
print(String(data: data, encoding: .utf8)!)
semaphore.signal()
}
task.resume()
semaphore.wait()
print("end")
But I got now a 401 error. For some reason the basic Auth is not being accepted by the code or by the server.
I checked the user and password and they are correct.
I find out the fix for my problem.
I was using "http://MY_ENDPOINT/validaResenha" in my constants file instead of using "https://MY_ENDPOINT/validaResenha".
After add the "s" to "http" letter (it becomes "https") everything starts to work for me.
The strange part is that GET and PUT methods works fine because of the redirect from HTTP to HTTPS, but in the case of POST calls, I got this error.
It's fixed now.
iOS block HTTP use HTTPS or add to your Info.plist file

print response body instead of header

My current code prints the header information, but I want the body response. I'm trying to obtain a token to use for another request.
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
if (error != nil) {
print(error!)
} else {
let httpResponse = response as? HTTPURLResponse
print(httpResponse!)
}})
dataTask.resume()
The content of the response is in the data variable of the completion block of dataTask(with: request).

a solution to retrieve information when they're no internet connection

On my app I have a form which the user can complete and send it to us with a SOAP request.
the form sended:
But I have a problem, I they're no internet connection I can't send the data by using my SOAP request.
So firstly I save the request in Core Data, so here it's ok... And when the user is on the app I do a scheduled request to see if they're a request in Core Data to send them.
But what about if the app is not running ? In Android I use background service, but with Apple it's impossible:
Android Services equivalent in iOS Swift
Someone have an idea to retrieve the data ?
Soap function:
func soapCall(fonction:String, soapMessageParamsTab:[SoapMessageParams], completion: #escaping (_ strData: NSString)-> ()/*, completion: #escaping (_ result: Int, _ resultContactWebId: Int)->()*/){
let soapRequest = AEXMLDocument()
let attributes = ["xmlns:SOAP-ENV" : "http://schemas.xmlsoap.org/soap/envelope/", "xmlns:ns1" : namespace, "xmlns:xsd" : "http://www.w3.org/2001/XMLSchema", "xmlns:xsi" : "http://www.w3.org/2001/XMLSchema-instance", "xmlns:SOAP-ENC" : "http://schemas.xmlsoap.org/soap/encoding/", "SOAP-ENV:encodingStyle" : "http://schemas.xmlsoap.org/soap/encoding/"]
let envelope = soapRequest.addChild(name: "SOAP-ENV:Envelope", attributes: attributes)
let body = envelope.addChild(name: "SOAP-ENV:Body")
let sendLead = body.addChild(name: "ns1:"+fonction)
for obj in soapMessageParamsTab {
sendLead.addChild(name: obj.soapName, value: obj.soapValue, attributes: ["xsi:type" : "xsd:"+obj.soapType])
}
//sendLead.addChild(name: "xml", value: messageSoap, attributes: ["xsi:type" : "xsd:string"])
let soapMessage = soapRequest.xmlString
let messageSoapMinify = minify(soapMessage)
// URL Soap
let urlString = soapServiceURL
let url = URL(string: urlString)
var theRequest = URLRequest(url: url!)
// Taille SoapMessage
let msgLength = String(messageSoapMinify.characters.count)
// Soap Login
let username = soapUsername
let password = soapPassword
let loginString = NSString(format: "%#:%#", username, password)
let loginData: Data = loginString.data(using: String.Encoding.utf8.rawValue)!
let base64LoginString = loginData.base64EncodedString(options: NSData.Base64EncodingOptions.lineLength64Characters)
// Requete Soap
theRequest.addValue("text/xml; charset=utf-8", forHTTPHeaderField: "Content-Type")
theRequest.addValue("Keep-Alive", forHTTPHeaderField: "Connection")
theRequest.addValue(msgLength, forHTTPHeaderField: "Content-Length")
theRequest.addValue("urn:ResponseAction", forHTTPHeaderField: "SOAPAction")
theRequest.httpMethod = "POST"
theRequest.httpBody = messageSoapMinify.data(using: String.Encoding.utf8, allowLossyConversion: true)
theRequest.addValue("Basic \(base64LoginString)", forHTTPHeaderField: "Authorization")
// print("Request is \(theRequest.allHTTPHeaderFields!)")
let session = Foundation.URLSession.shared
let task = session.dataTask(with: theRequest, completionHandler: {data, response, error -> Void in
if error != nil
{
print(error?.localizedDescription)
}
//print("Response Login: \(response)")
//print("Error Login: \(error)")
let strData = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)!
//print("Body Login: \(strData)")
completion(strData)
})
task.resume()
}
Using NSURLSession with background configuration you should be ok.
Note: If the app is explicitly killed by the user the scheduled request will be cancelled. This trick works just if the app was killed by the system for any reason (low memory, crash etc...). There is nothing you can do if the app was killed by the user. The background fetch might be a solution, but it will be decided by iOS if and when to awake the app for the opportunistic fetch.
This could help you:
https://blog.newrelic.com/2016/01/13/ios9-background-execution/
Edit:
This tutorial could be useful as well: https://www.raywenderlich.com/110458/nsurlsession-tutorial-getting-started

NSURLSession parameters not recognized

Im attemping to make a HTTPRequest using NSURLSession. When I set the full url the request returns the correct data but when using parameters (NSJSONSerialization.dataWithJSONObject -> HTTPBody I get this error
error Domain=NSURLErrorDomain Code=-1005 "The network connection was lost."
is there something im doing wrong here?
let json = ["api_key": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"]
do {
let jsonData = try NSJSONSerialization.dataWithJSONObject(json, options: .PrettyPrinted)
let url = NSURL(string: "https://api.themoviedb.org/3/discover/movie")!
let request = NSMutableURLRequest(URL: url)
request.HTTPBody = jsonData
request.HTTPMethod = "GET"
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
let task = NSURLSession.sharedSession().dataTaskWithRequest(request){ data, response, error in
if error != nil{
print("Error -> \(error)")
return
}
do {
let result = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? [String:AnyObject]
print("Result -> \(result)")
} catch {
print("Error -> \(error)")
}
}
task.resume()
} catch {
print(error)
}
}
This is not a duplicate! I looked at the suggested answer (none of them worked) before asking this question
In your case that issue can be solved by changing the request.HTTPMethod = "GET" to request.HTTPMethod = "POST"
You should not send HTTP Body in the get request, to send the data with the body you should change HTTPMethod to post
Note: Please check if this api method supports POST requests, if it don't support post you can't use it with http body/post, as per doc i only find 'get' request for the discover/movie which can be like this:
let url = NSURL(string: "http://api.themoviedb.org/3/discover/movie?api_key=YOUR_API_KEY")!
let request = NSMutableURLRequest(URL: url)
request.addValue("application/json", forHTTPHeaderField: "Accept")
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(request) { data, response, error in
if let response = response, data = data {
print(response)
print(String(data: data, encoding: NSUTF8StringEncoding))
} else {
print(error)
}
}
task.resume()
Ref: You can check more information from this url: http://docs.themoviedb.apiary.io/#reference/discover/discovermovie/get

Swift Send Email with MailGun

Problem
I would like to use the MailGun service to send emails from a pure Swift app.
Research So Far
As I understand it, there are two methods to send an email via MailGun. One is to email MailGun with the emails, and MailGun will redirect it (See Send via SMTP). That will, as I understand it, not work, as iOS cannot programatically automatically send mail, and must use methods that require user intervention. As such, I should use the API directly. As I understand it, I need to open a URL to do this, and so I should use some form of NSURLSession, as per this SO answer
Code
MailGun provides documentation for Python, which is as follows:
def send_simple_message():
return requests.post(
"https://api.mailgun.net/v3/sandbox(Personal info).mailgun.org/messages",
auth=("api", "key-(Personal info)"),
data={"from": "Excited User <(Personal info)>",
"to": ["bar#example.com", "(Personal info)"],
"subject": "Hello",
"text": "Testing some Mailgun awesomness!"})
with (Personal info) being substituted for keys/information/emails.
Question
How do I do that in Swift?
Thanks!
In python, the auth is being passed in the header.
You have to do a http post request, passing both the header and the body.
This is a working code:
func test() {
let session = NSURLSession.sharedSession()
let request = NSMutableURLRequest(URL: NSURL(string: "https://api.mailgun.net/v3/sandbox(Personal info).mailgun.org/messages")!)
request.HTTPMethod = "POST"
let data = "from: Excited User <(Personal info)>&to: [bar#example.com,(Personal info)]&subject:Hello&text:Testinggsome Mailgun awesomness!"
request.HTTPBody = data.dataUsingEncoding(NSASCIIStringEncoding)
request.setValue("key-(Personal info)", forHTTPHeaderField: "api")
let task = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in
if let error = error {
print(error)
}
if let response = response {
print("url = \(response.URL!)")
print("response = \(response)")
let httpResponse = response as! NSHTTPURLResponse
print("response code = \(httpResponse.statusCode)")
}
})
task.resume()
}
people are getting 400 or 401 errors because none of the other answers construct the url correctly. here is some code that works in swift 5 and iOS15:
func sendEmail() {
// variablize our https path with API key, recipient and message text
let mailgunAPIPath = "https://api:YOUR_API_KEY#api.mailgun.net/v3/YOUR_DOMAIN/messages?"
let emailRecipient = "RECIPIENT#EMAIL.COM"
let emailMessage = "Testing%20email%20sender%20variables"
// Create a session and fill it with our request
let session = URLSession.shared
let request = NSMutableURLRequest(url: NSURL(string: mailgunAPIPath + "from=USER#YOUR_DOMAIN&to=\(emailRecipient)&subject=A%20New%20Test%21&text=\(emailMessage)")! as URL)
// POST and report back with any errors and response codes
request.httpMethod = "POST"
let task = session.dataTask(with: request as URLRequest, completionHandler: {(data, response, error) in
if let error = error {
print(error)
}
if let response = response {
print("url = \(response.url!)")
print("response = \(response)")
let httpResponse = response as! HTTPURLResponse
print("response code = \(httpResponse.statusCode)")
}
})
task.resume()
}
requests.post sends an HTTP POST request, encoding key/value pairs as application/x-www-form-urlencoded. You need to do the same.
convert the set of key-value pairs into application/x-www-form-urlencoded as per How to escape the HTTP params in Swift
compose the request using the resulting string for data & send it as per iOS : http Post using swift
I spent hours trying to get the selected answer working, but to no avail.
Although I was finally able to get this working properly with a large HTTP response. I put the full path into Keys.plist so that I can upload my code to github and broke out some of the arguments into variables so I can have them programmatically set later down the road.
// Email the FBO with desired information
// Parse our Keys.plist so we can use our path
var keys: NSDictionary?
if let path = NSBundle.mainBundle().pathForResource("Keys", ofType: "plist") {
keys = NSDictionary(contentsOfFile: path)
}
if let dict = keys {
// variablize our https path with API key, recipient and message text
let mailgunAPIPath = dict["mailgunAPIPath"] as? String
let emailRecipient = "bar#foo.com"
let emailMessage = "Testing%20email%20sender%20variables"
// Create a session and fill it with our request
let session = NSURLSession.sharedSession()
let request = NSMutableURLRequest(URL: NSURL(string: mailgunAPIPath! + "from=FBOGo%20Reservation%20%3Cscheduler#<my domain>.com%3E&to=reservations#<my domain>.com&to=\(emailRecipient)&subject=A%20New%20Reservation%21&text=\(emailMessage)")!)
// POST and report back with any errors and response codes
request.HTTPMethod = "POST"
let task = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in
if let error = error {
print(error)
}
if let response = response {
print("url = \(response.URL!)")
print("response = \(response)")
let httpResponse = response as! NSHTTPURLResponse
print("response code = \(httpResponse.statusCode)")
}
})
task.resume()
}
The Mailgun Path is in Keys.plist as a string called mailgunAPIPath with the value:
https://API:key-<my key>#api.mailgun.net/v3/<my domain>.com/messages?
Hope this offers a solution to anyone else having issues with MailGun and wanting to avoid a 3rd party solution!
Swift 3 answer:
func test() {
let session = URLSession.shared
var request = URLRequest(url: URL(string: "https://api.mailgun.net/v3/sandbox(Personal info).mailgun.org/messages")!)
request.httpMethod = "POST"
let data = "from: Excited User <(Personal info)>&to: [bar#example.com,(Personal info)]&subject:Hello&text:Testinggsome Mailgun awesomness!"
request.httpBody = data.data(using: .ascii)
request.setValue("key-(Personal info)", forHTTPHeaderField: "api")
let task = session.dataTask(with: request, completionHandler: {(data, response, error) in
if let error = error {
print(error)
}
if let response = response {
print("url = \(response.url!)")
print("response = \(response)")
let httpResponse = response as! HTTPURLResponse
print("response code = \(httpResponse.statusCode)")
}
})
task.resume()
}