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

Android应用使用OKHttp调用SendGrid发送带附件邮件问题咨询

Fixing SendGrid Attachment Issues with OkHttp on Android

Hey there! Let’s tackle this SendGrid + OkHttp attachment problem you’re facing. The good news is you don’t have to use byte arrays exclusively—there are workarounds depending on your use case. Here are the most practical solutions:

1. Troubleshoot the "file send" method first

Chances are the file approach isn’t working because of incorrect MultipartBody setup or Android storage permissions, not because OkHttp can’t handle files. SendGrid’s API expects specific fields for attachments, so double-check your request structure.

Here’s a corrected example of sending a file via OkHttp:

import okhttp3.*
import java.io.File

fun sendEmailWithAttachment(filePath: String) {
    val apiKey = "YOUR_SENDGRID_API_KEY"
    val file = File(filePath)
    
    // Verify file exists and is readable (critical for Android 10+ scoped storage)
    if (!file.exists() || !file.canRead()) {
        // Handle file access error (check permissions, use ContentResolver if needed)
        return
    }

    val fileRequestBody = RequestBody.create(MediaType.parse("application/pdf"), file)
    val multipartBody = MultipartBody.Builder()
        .setType(MultipartBody.FORM)
        // Email metadata
        .addFormDataPart("personalizations[0][to][0][email]", "recipient@example.com")
        .addFormDataPart("from[email]", "your-sender@example.com")
        .addFormDataPart("subject", "Test Email with Attachment")
        .addFormDataPart("content[0][type]", "text/plain")
        .addFormDataPart("content[0][value]", "Check out the attached file!")
        // Attachment fields (SendGrid requires these)
        .addFormDataPart("attachments[0][content]", "", fileRequestBody)
        .addFormDataPart("attachments[0][filename]", file.name)
        .addFormDataPart("attachments[0][type]", "application/pdf")
        .addFormDataPart("attachments[0][disposition]", "attachment")
        .build()

    val request = Request.Builder()
        .url("https://api.sendgrid.com/v3/mail/send")
        .header("Authorization", "Bearer $apiKey")
        .post(multipartBody)
        .build()

    val client = OkHttpClient()
    client.newCall(request).enqueue(object : Callback {
        override fun onFailure(call: Call, e: IOException) {
            // Handle network failure
            e.printStackTrace()
        }

        override fun onResponse(call: Call, response: Response) {
            // Check SendGrid's response code (202 means success)
            println("Response code: ${response.code()}")
            response.close()
        }
    })
}

Key fixes to check:

  • Ensure your app has READ_EXTERNAL_STORAGE permission (or use scoped storage APIs for Android 10+)
  • Include all required SendGrid attachment fields: content, filename, type, and disposition
  • Verify the media type matches your file (e.g., image/png for images, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet for Excel files)

2. Convert input streams to temporary files (great for large files)

If you’re working with input streams (e.g., from assets, network, or in-memory data), you can write the stream to a temporary file in your app’s cache directory. This avoids loading the entire file into memory (which prevents OOM for large attachments).

Example code to convert an input stream to a temp file:

import android.content.Context
import java.io.File
import java.io.InputStream

fun inputStreamToTempFile(inputStream: InputStream, context: Context): File {
    val tempFile = File.createTempFile("sendgrid_attachment", ".tmp", context.cacheDir)
    tempFile.outputStream().use { outputStream ->
        inputStream.copyTo(outputStream)
    }
    // Optional: Delete temp file after sending
    tempFile.deleteOnExit()
    return tempFile
}

// Usage (e.g., from assets)
val inputStream = context.assets.open("report.pdf")
val tempFile = inputStreamToTempFile(inputStream, context)
sendEmailWithAttachment(tempFile.absolutePath)

3. Use byte arrays (for small files only)

If your attachment is small (under a few MB), converting the input stream to a byte array is a quick solution. Just be cautious—large files will cause memory issues.

Example:

fun inputStreamToByteArray(inputStream: InputStream): ByteArray {
    return inputStream.use { it.readBytes() }
}

// Usage
val inputStream = ... // Your input stream
val attachmentBytes = inputStreamToByteArray(inputStream)
val byteRequestBody = RequestBody.create(MediaType.parse("application/pdf"), attachmentBytes)

// Add to MultipartBody:
multipartBody.addFormDataPart("attachments[0][content]", "", byteRequestBody)
// Don't forget to add filename, type, and disposition fields as before

Final Recommendation

  • For most cases: Fix the file send method first—it’s the most memory-efficient and aligns with OkHttp’s strengths.
  • For input streams: Use temporary files if dealing with large data; reserve byte arrays for small attachments.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 07:02:04