You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift调用Mailgun API返回401错误:未提供有效API密钥求助

排查Mailgun API 401错误和请求体格式问题

我来帮你一步步解决这两个问题,先搞定最棘手的401认证错误,再调整请求体格式:

1. 修复401 "No valid API key provided" 错误

你碰到这个问题大概率是Base64编码方式不对——Swift的String默认没有toBase64()方法,你用的自定义方法可能编码逻辑出了问题。正确的Basic Auth编码应该把凭证字符串转成Data,再生成Base64:

let credentials = "api:key-################################-########-########"
// 替换你原来的toBase64()调用,用标准方式生成Base64编码
let authData = Data(credentials.utf8).base64EncodedString()
request.setValue("Basic \(authData)", forHTTPHeaderField: "Authorization")

另外再核对两个细节:

  • 确保URL里的sandbox域名和Mailgun控制台Sending Domains里的地址完全一致,比如https://api.mailgun.net/v3/sandboxxxxxxxxxxxxx.mailgun.org/messages
  • 确认私钥是从Account Security页面复制的Private API Key,不是Public Key

2. 修正请求体格式错误

你的请求体有几处不符合Mailgun的application/x-www-form-urlencoded格式要求:

  • from字段:不需要给邮箱加括号,正确写法是from: Swift Email <test@test.com>
  • to字段:直接用逗号分隔多个邮箱,去掉方括号和额外括号,比如to: myemail@gmail.com,myemail@gmail.com
  • 建议显式设置Content-Type请求头,避免服务端解析异常

修正后的完整代码

func email() {
    guard let url = URL(string: "https://api.mailgun.net/v3/sandbox################################/messages") else {
        print("Invalid URL")
        return
    }
    
    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    
    // 正确的认证头处理
    let credentials = "api:key-################################-########-########"
    let authData = Data(credentials.utf8).base64EncodedString()
    request.setValue("Basic \(authData)", forHTTPHeaderField: "Authorization")
    
    // 显式设置Content-Type,确保服务端正确解析请求体
    request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
    
    // 修正格式后的请求体
    let postData = "from: Swift Email <test@test.com>&to: myemail@gmail.com,myemail@gmail.com&subject:Hello&text:Testing_some_Mailgun_awesomness"
    request.httpBody = postData.data(using: .ascii)
    
    let task = URLSession.shared.dataTask(with: request) { data, response, error in
        if let error = error {
            print("Error: \(error.localizedDescription)")
            return
        }
        
        guard let httpResponse = response as? HTTPURLResponse else {
            print("Invalid response")
            return
        }
        
        print("Status Code: \(httpResponse.statusCode)")
        print("Response URL: \(httpResponse.url?.absoluteString ?? "N/A")")
        
        // 可选:打印响应内容,方便进一步排查问题
        if let data = data, let responseString = String(data: data, encoding: .utf8) {
            print("Response Body: \(responseString)")
        }
    }
    task.resume()
}

额外排查建议

如果还是报错,可以试试这两步:

  • 用Postman之类的工具先手动测试API,确认私钥、域名和请求体格式没问题,排除代码外的因素
  • 检查是否有防火墙或代理拦截了请求,导致认证头丢失

内容的提问来源于stack exchange,提问作者nickcoding

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 08:33:01