發送電子郵件時,希望圖片直接顯示在郵件正文中 (內嵌),而非作為附件。
標準 SMTP/MIME 郵件協定中,正文只能是純文字或 HTML。圖片必須作為附件 (Content-Disposition: attachment) 或內嵌資源 (Content-Disposition: inline + Content-ID),並在 HTML 中用 <img src=\"cid:xxx\"> 引用。
Android ACTION_SEND Intent **不支援**直接構建 multipart/related MIME 結構,因此無法透過 Intent 直接發送內嵌圖片郵件。
| 方案 | 可行性 | 說明 |
|---|---|---|
| Intent + EXTRA_STREAM (附件) | ✅ 完整支援 | 圖片作為附件,收件端決定是否顯示 |
| Intent + HTML 正文 + 外部圖片連結 | ✅ 可行 | <img src=\"https://example.com/image.jpg\">,需圖片公開可訪問 |
| Intent 內嵌圖片 (cid:) | ❌ 不支援 | Android Intent 無法構建 multipart/related |
| JavaMail API 直接發送 | ✅ 完整控制 | 需帳號密碼/Token,適合後台自動發送 |
Intent emailIntent = new Intent(Intent.ACTION_SEND);
emailIntent.setType("text/html"); // 關鍵:HTML 類型
emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[]{"recipient@example.com"});
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "嵌入圖片測試");
emailIntent.putExtra(Intent.EXTRA_TEXT,
Html.fromHtml("標題
內文...
",
Html.FROM_HTML_MODE_LEGACY));
startActivity(Intent.createChooser(emailIntent, "選擇郵件應用"));
前提:圖片已上傳至公開可訪問的 HTTPS URL。
// 需加入依賴: implementation 'com.sun.mail:javax.mail:1.6.2' (或 Android 版)
public void sendEmbeddedImageEmail() {
new Thread(() -> {
try {
Properties props = new Properties();
props.put("mail.smtp.host", "smtp.gmail.com");
props.put("mail.smtp.port", "587");
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.starttls.enable", "true");
Session session = Session.getInstance(props, new Authenticator() {
@Override protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("your@gmail.com", "app_password");
}
});
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress("your@gmail.com"));
message.setRecipients(Message.RecipientType.TO, InternetAddress.parse("to@example.com"));
message.setSubject("內嵌圖片郵件");
// 建立 multipart/related
MimeMultipart multipart = new MimeMultipart("related");
// HTML 正文部件
MimeBodyPart htmlPart = new MimeBodyPart();
String html = "內嵌圖片
";
htmlPart.setContent(html, "text/html; charset=utf-8");
multipart.addBodyPart(htmlPart);
// 圖片部件 (內嵌)
MimeBodyPart imagePart = new MimeBodyPart();
// 從 assets/raw/res 讀取或從檔案
InputStream is = getAssets().open("embedded_image.jpg");
DataSource fds = new ByteArrayDataSource(is, "image/jpeg");
imagePart.setDataHandler(new DataHandler(fds));
imagePart.setHeader("Content-ID", ""); // 對應 cid:image1
imagePart.setDisposition(MimeBodyPart.INLINE);
multipart.addBodyPart(imagePart);
message.setContent(multipart);
Transport.send(message);
runOnUiThread(() -> Toast.makeText(this, "發送成功", Toast.LENGTH_SHORT).show());
} catch (Exception e) {
e.printStackTrace();
runOnUiThread(() -> Toast.makeText(this, "發送失敗: " + e.getMessage(), Toast.LENGTH_LONG).show());
}
}).start();
}
Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
intent.setType("image/*");
intent.putExtra(Intent.EXTRA_EMAIL, new String[]{"to@example.com"});
intent.putExtra(Intent.EXTRA_SUBJECT, "分享圖片");
intent.putExtra(Intent.EXTRA_TEXT, "正文內容");
// 多張圖片 URI
ArrayList uris = new ArrayList<>();
uris.add(FileProvider.getUriForFile(this, AUTHORITY, new File(path1)));
uris.add(FileProvider.getUriForFile(this, AUTHORITY, new File(path2)));
intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(Intent.createChooser(intent, "分享圖片"));
ACTION_SEND_MULTIPLE 附件方式,最通用、無需帳號密碼