如何用Volley在Android中通过SendGrid V3 API编程发送邮件
在Android中用Volley调用SendGrid V3 API发送邮件
第一步:准备工作
- 先确保你已经在SendGrid控制台拿到了API Key,记得给这个密钥开启邮件发送权限
- 在Android项目里添加Volley依赖:打开
app/build.gradle(Module级别的文件),在dependencies块里加入:implementation 'com.android.volley:volley:1.2.1' - 最后在
AndroidManifest.xml中添加网络权限,不然没法发起请求:<uses-permission android:name="android.permission.INTERNET" />
第二步:编写完整的Volley请求代码
SendGrid V3的邮件发送接口是https://api.sendgrid.com/v3/mail/send,需要发POST请求,请求体是JSON格式。下面是可以直接用的示例代码,我把它放在Activity里了,你也可以根据需求移到ViewModel或者其他组件:
import com.android.volley.Request; import com.android.volley.RequestQueue; import com.android.volley.Response; import com.android.volley.VolleyError; import com.android.volley.toolbox.JsonObjectRequest; import com.android.volley.toolbox.Volley; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.util.HashMap; import java.util.Map; import android.os.Bundle; import android.widget.Button; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; public class MainActivity extends AppCompatActivity { private RequestQueue requestQueue; // 这里替换成你的SendGrid API Key,记得后面要换安全存储方式! private static final String SENDGRID_API_KEY = "your-sendgrid-api-key"; private static final String SENDGRID_API_URL = "https://api.sendgrid.com/v3/mail/send"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 初始化Volley请求队列 requestQueue = Volley.newRequestQueue(this); // 绑定按钮点击事件,触发邮件发送 Button sendBtn = findViewById(R.id.send_email_btn); sendBtn.setOnClickListener(v -> sendTestEmail()); } private void sendTestEmail() { // 构造SendGrid要求的JSON请求体 JSONObject requestBody = new JSONObject(); try { // 发件人信息(要在SendGrid控制台验证过) JSONObject from = new JSONObject(); from.put("email", "your-verified-sender@example.com"); from.put("name", "你的发件人名称"); requestBody.put("from", from); // 收件人列表,支持多个收件人,这里先写一个 JSONArray recipients = new JSONArray(); JSONObject to = new JSONObject(); to.put("email", "recipient@example.com"); to.put("name", "收件人名称"); recipients.put(to); requestBody.put("personalizations", new JSONArray().put(new JSONObject().put("to", recipients))); // 邮件主题和内容 requestBody.put("subject", "来自Android的测试邮件"); JSONObject content = new JSONObject(); content.put("type", "text/plain"); // 也可以用text/html发富文本邮件 content.put("value", "这是通过Volley调用SendGrid API发送的测试邮件!"); requestBody.put("content", new JSONArray().put(content)); } catch (JSONException e) { e.printStackTrace(); Toast.makeText(this, "构造邮件内容失败", Toast.LENGTH_SHORT).show(); return; } // 创建POST请求 JsonObjectRequest sendEmailRequest = new JsonObjectRequest( Request.Method.POST, SENDGRID_API_URL, requestBody, new Response.Listener<JSONObject>() { @Override public void onResponse(JSONObject response) { // SendGrid成功接收请求会返回202状态码,这里提示发送成功 Toast.makeText(MainActivity.this, "邮件发送成功!", Toast.LENGTH_SHORT).show(); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { // 失败时提示错误,同时打印详细错误信息到Logcat String errorMsg = "发送失败:" + (error.getMessage() != null ? error.getMessage() : "未知错误"); Toast.makeText(MainActivity.this, errorMsg, Toast.LENGTH_LONG).show(); if (error.networkResponse != null) { try { String errorDetail = new String(error.networkResponse.data, "UTF-8"); android.util.Log.e("SendGridError", "错误详情:" + errorDetail); } catch (Exception e) { e.printStackTrace(); } } } } ) { // 设置请求头:必须带上Authorization和Content-Type @Override public Map<String, String> getHeaders() { Map<String, String> headers = new HashMap<>(); headers.put("Authorization", "Bearer " + SENDGRID_API_KEY); headers.put("Content-Type", "application/json"); return headers; } }; // 将请求加入Volley队列执行 requestQueue.add(sendEmailRequest); } }
第三步:关键注意事项
- API Key安全:绝对不要把API Key硬编码在代码里!建议用Android Keystore或者加密的SharedPreferences存储,防止APK被逆向后泄露密钥,导致你的SendGrid账户被滥用。
- 发件人验证:SendGrid要求必须验证发件人邮箱或域名,否则邮件会被拒绝或者直接进垃圾邮件,记得先在SendGrid控制台完成验证步骤。
- 错误排查:如果发送失败,去Logcat里找
SendGridError标签,SendGrid会返回非常详细的错误原因,比如API Key无效、收件人格式错误、发件人未验证等。 - 线程处理:Volley会自动在后台线程执行网络请求,回调会回到主线程,所以你不用手动处理线程切换,直接在回调里更新UI就行。
内容的提问来源于stack exchange,提问作者Cornelius Roemer




