Xamarin Essentials添加邮件附件抛出System.InvalidOperationException问题求助
问题根源分析
这个问题我之前帮同事排查过好几次,核心问题基本都是Android 7.0+的文件URI访问限制和FileProvider配置缺失导致的——你虽然能读写自己应用的私有文件,但邮件应用没有权限直接访问这些路径,所以触发了System.InvalidOperationException。Xamarin.Essentials的Email API在处理附件时依赖系统的文件共享机制,没配置的话自然会报错。
解决步骤(针对Android平台)
1. 配置AndroidManifest.xml
在项目的AndroidManifest.xml的<application>节点内添加FileProvider的配置:
<provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider>
authorities要确保是你的应用包名加上.fileprovider(比如com.yourcompany.yourapp.fileprovider),${applicationId}会自动替换为你的项目包名。exported必须设为false,因为FileProvider不需要对外公开;grantUriPermissions设为true,允许临时授权邮件应用访问文件。
2. 创建文件共享路径配置
在Android项目的Resources/xml目录下新建file_paths.xml文件(没有xml目录就手动创建一个),根据你使用的存储目录选择对应的节点:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 对应FileSystem.CacheDirectory(应用私有缓存目录) --> <cache-path name="app_cache" path="." /> <!-- 对应System.Environment.SpecialFolder.LocalApplicationData(应用私有文件目录) --> <files-path name="app_files" path="." /> </paths>
path="."表示共享该目录下的所有文件和子目录,你也可以指定具体子路径缩小共享范围。
3. 修改代码:用Content URI传递附件
不要直接把私有文件路径传给EmailAttachment,而是通过FileProvider生成可共享的content://格式URI:
using AndroidX.Core.Content; using Java.IO; // 假设你的文件路径是filePath var targetFile = new File(filePath); var contentUri = FileProvider.GetUriForFile( Android.App.Application.Context, $"{Android.App.Application.Context.PackageName}.fileprovider", targetFile ); // 构造邮件并添加附件 var emailMessage = new EmailMessage { Subject = "附件测试邮件", Body = "这是带附件的测试内容", To = new List<string> { "test@example.com" }, Attachments = new List<EmailAttachment> { new EmailAttachment(contentUri.ToString()) } }; await Email.ComposeAsync(emailMessage);
注意:如果项目还没引用AndroidX.Core NuGet包,先在NuGet管理器里安装它。
额外检查点
- 确认文件存在:在添加附件前用
File.Exists(filePath)验证,避免因文件不存在触发异常。 - Android 10+(API 29)及以上不需要申请
MANAGE_EXTERNAL_STORAGE权限,因为我们共享的是应用私有文件,FileProvider已经处理了权限逻辑。 - 如果是iOS平台,只需确保文件放在
NSDocumentDirectory或NSTemporaryDirectory,Xamarin.Essentials会自动处理沙箱权限,大概率还是Android的配置问题。
内容的提问来源于stack exchange,提问作者Gerald Myers
相关产品推荐
相关产品推荐

