Swift 使用 MailGun 发送电子邮件

Swift Send Email with MailGun

问题

我想使用 MailGun 服务从纯 Swift 应用程序发送电子邮件。

目前的研究

据我了解,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

代码

MailGun为Python提供了文档,如下:

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!"})

用(个人信息)代替 keys/information/emails。

问题

如何在 Swift 中执行此操作?

谢谢!

requests.post 发送 HTTP POST 请求,将 key/value 对编码为 application/x-www-form-urlencoded。你也需要这样做。

  • 根据
  • 将键值对集合转换为application/x-www-form-urlencoded
  • 使用生成的数据字符串编写请求并按照
  • 发送

在 python 中,auth 正在 header 中传递。

您必须执行一个 http post 请求,同时传递 header 和 body。

这是一个工作代码:

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()
    }

我花了几个小时试图让所选答案生效,但无济于事。

虽然我最终能够通过大型 HTTP 响应使其正常工作。我将完整路径放入 Keys.plist,这样我就可以将我的代码上传到 github,并将一些参数分解为变量,这样我就可以在以后以编程方式设置它们。

// 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()
}

Mailgun 路径在 Keys.plist 中作为一个名为 mailgunAPIPath 的字符串,其值为:

https://API:key-<my key>@api.mailgun.net/v3/<my domain>.com/messages?

希望这能为遇到 MailGun 问题并希望避免第 3 方解决方案的任何其他人提供解决方案!

Swift 3 个回答:

    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()
    }

人们收到 400 或 401 错误,因为 none 的其他答案正确构建了 url。这是一些适用于 swift 5 和 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()
}