UWP中摄像头拍摄照片作为邮件附件发送后无法打开的问题
解决摄像头照片作为邮件附件无法打开的问题
我太懂这种挫败感了——换了两个SMTP库,邮件都能顺利发出去,但附件图片死活打不开,肯定是图像数据的处理环节出了问题。你怀疑格式问题完全没错,大概率是摄像头捕获的原始帧没有被正确编码为有效的JPEG格式,直接把原始流/字节传出去,附件自然是损坏的。
下面针对你用的两个库分别给出修复方案,先从最核心的图像编码步骤说起:
第一步:先把摄像头捕获的帧转成有效的JPEG数据
摄像头捕获的CapturedPhoto.Frame通常是原始像素格式(比如YUV或者NV12),不是直接可用的JPG流。你需要先把它编码成JPEG格式的字节流,再用来生成附件。这里给你一个通用的转换方法:
private async Task<byte[]> ConvertFrameToJpegBytes(CapturedPhoto photo) { using (var stream = photo.Frame.CloneStream()) { var decoder = await BitmapDecoder.CreateAsync(stream); var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, stream); // 设置编码参数,可根据需求调整质量 encoder.BitmapTransform.ScaledWidth = decoder.PixelWidth; encoder.BitmapTransform.ScaledHeight = decoder.PixelHeight; encoder.IsThumbnailGenerated = false; encoder.Quality = 80; await encoder.FlushAsync(); // 重置流位置并读取字节 stream.Seek(0); var bytes = new byte[stream.Size]; await stream.ReadAsync(bytes.AsBuffer(), (uint)stream.Size, InputStreamOptions.None); return bytes; } }
这个方法会把原始帧解码后重新编码为JPEG,确保输出的是有效的JPG字节数据。
针对LightBuzz.SMTP的修改
你原来的代码直接用image.Frame.CloneStream()创建附件,但这个流是原始帧格式,不是JPG。修改成使用上面的转换方法,把JPEG字节转成RandomAccessStreamReference:
private async Task<SmtpResult> SendAlertEmail(List<CapturedPhoto> images) { using (SmtpClient client = new SmtpClient("smtp.gmail.com", 465, true, "mygmail@gmail.com", "myPassword")) { EmailMessage emailMessage = new EmailMessage(); emailMessage.Sender.Address = "IoTAlertApp@donotreply.com"; emailMessage.Sender.Name = "IoT App"; emailMessage.To.Add(new EmailRecipient("myemail@gmail.com")); emailMessage.Subject = "ALERT | MOTION DETECTED"; emailMessage.Body = "This is an email sent from a UWP app!"; if (images.Any()) { int imageCount = 1; string fileName = $"image_{imageCount}_{DateTime.Now.Ticks}.jpg"; var jpegBytes = await ConvertFrameToJpegBytes(images[0]); // 把JPEG字节转成内存流 using (var stream = new InMemoryRandomAccessStream()) { await stream.WriteAsync(jpegBytes.AsBuffer()); stream.Seek(0); RandomAccessStreamReference reference = RandomAccessStreamReference.CreateFromStream(stream); emailMessage.Attachments.Add(new EmailAttachment(fileName, reference)); } } images.Clear(); SmtpResult result = await client.SendMailAsync(emailMessage); return result; } }
关键变化:先把原始帧转成JPEG字节,再写入内存流,用这个内存流创建附件引用,确保附件是有效的JPG文件。
针对EASendMailRT的修改
你的代码里传入的byte[] image如果是原始帧数据,那肯定不行。修改成用上面的转换方法生成JPEG字节,再传入:
private async Task Send_Email(CapturedPhoto photo) { String Result = ""; try { SmtpMail oMail = new SmtpMail("TryIt"); SmtpClient oSmtp = new SmtpClient(); oMail.From = new MailAddress("IoTSquatter@DoNotReply.com"); oMail.To.Add(new MailAddress("myemail@gmail.com")); oMail.Subject = "ALERT | MOTION DETECTED"; SmtpServer oServer = new SmtpServer("smtp.gmail.com"); oServer.User = "myemail@gmail.com"; oServer.Password = "password"; // 注意:Gmail建议用应用专用密码,不要用明文账号密码 oServer.Port = 465; oServer.ConnectType = SmtpConnectType.ConnectSSLAuto; // 先把捕获的照片转成JPEG字节 var jpegBytes = await ConvertFrameToJpegBytes(photo); Attachment oAttachment = oMail.AddAttachment("testImage.jpg", jpegBytes); string contentID = "test001@host"; oAttachment.ContentID = contentID; oMail.HtmlBody = $"<html><body>this is an <img src=\"cid:{contentID}\"> embedded picture.</body></html>"; await oSmtp.SendMailAsync(oServer, oMail); Result = "Email was sent successfully!"; } catch (Exception ep) { Result = String.Format("Failed to send email with the following error: {0}", ep.Message); } }
另外提醒:Gmail现在不允许直接用账号密码登录SMTP,建议开启两步验证后使用应用专用密码,否则可能会被拒绝登录。
额外排查步骤
- 本地测试编码结果:把转换后的JPEG字节保存到本地文件,看看能不能正常打开。如果本地都打不开,说明编码环节有问题,需要检查
ConvertFrameToJpegBytes方法的参数(比如解码器是否正确识别原始帧格式)。 - 检查MIME类型:有些SMTP库需要显式指定附件的MIME类型为
image/jpeg,如果上面的修改后还是不行,可以尝试给Attachment添加ContentType属性(比如LightBuzz的EmailAttachment有没有ContentType设置项,EASendMailRT的Attachment会默认根据后缀识别,但也可以手动指定)。
内容的提问来源于stack exchange,提问作者DotNetRussell
相关产品推荐
相关产品推荐

