将大文件附加到 Outlook 邮件或事件
2021/8/12
本文内容
使用 Microsoft Graph API,可将最大 150 MB 的文件附加到 Outlook 邮件或 事件项目。 根据文件大小,选择以下两种方法之一来附加文件:
如果文件大小小于 3 MB,应该针对 Outlook 项的 附件 导航属性执行单个 POST;了解如何针对 邮件或 事件执行此操作。 成功的 POST 响应包括文件附件的 ID。
如果文件大小介于 3MB 和 150MB 之间,则创建一个上传会话,并以迭代的方式使用 PUT 来上传文件的字节范围,直到完整的文件上传完毕。 最后一个成功 PUT 响应中的标头包括带附件 ID 的 URL。
若要将多个文件附加到邮件,请根据每个文件的文件大小,选择相应的方法,并单独附加文件。
本文逐步介绍了第二种方法,创建并使用上传会话来添加大型文件附件(大小超过 3 MB)至 Outlook 项。 各步显示相应的邮件或事件代码。 成功上传整个文件后,文章显示获取含有文件附件 ID 的响应标头,随后显示使用附件 ID 来获取原始附件内容或附件元数据。
重要
如果要将大文件附加到共享或委派邮箱中的邮件或事件,请注意一个已知问题。
第 1 步:创建上传会话
创建上传会话,将文件附加到邮件或事件。 在输入参数 AttachmentItem 中指定文件。
成功的操作返回 HTTP 201 Created 和新的 uploadSession 实例,其中包含可在后续 PUT 操作中用于上传文件各部分的非跳转 URL。 uploadSession 提供一个临时存储位置,在此位置保存文件字节数,直到完整文件上传完毕。
响应中的 uploadSession 对象还包含 nextExpectedRanges 属性,这表明初始上传开始位置应该为 0 字节。
权限
请务必请求 Mail.ReadWrite 权限,以为邮件创建 uploadSession,并为事件创建 Calendars.ReadWrite。
新的 uploadSession 的 uploadUrl 属性中返回的非跳转 URL 经过预身份验证,包含针对 https://outlook.office.com 域中后续 PUT 查询的相应授权令牌。 该令牌会在 expirationDateTime 过期。 请勿自定义 PUT 操作的此 URL。
示例:创建邮件的上传会话
请求
POST https://graph.microsoft.com/v1.0/me/messages/AAMkADI5MAAIT3drCAAA=/attachments/createUploadSession
Content-type: application/json
{
"AttachmentItem": {
"attachmentType": "file",
"name": "flower",
"size": 3483322
}
}
GraphServiceClient graphClient = new GraphServiceClient( authProvider );
var attachmentItem = new AttachmentItem
{
AttachmentType = AttachmentType.File,
Name = "flower",
Size = 3483322
};
await graphClient.Me.Messages["AAMkADI5MAAIT3drCAAA="].Attachments
.CreateUploadSession(attachmentItem)
.Request()
.PostAsync();
阅读 SDK 文档 ,详细了解如何将 SDK 添加到项目并创建 authProvider 实例。
const options = {
authProvider,
};
const client = Client.init(options);
const uploadSession = {
AttachmentItem: {
attachmentType: "file",
name: "flower",
size: 3483322
}
};
let res = await client.api('/me/messages/AAMkADI5MAAIT3drCAAA=/attachments/createUploadSession')
.post(uploadSession);
阅读 SDK 文档 ,详细了解如何将 SDK 添加到项目并创建 authProvider 实例。
MSHTTPClient *httpClient = [MSClientFactory createHTTPClientWithAuthenticationProvider:authenticationProvider];
NSString *MSGraphBaseURL = @"https://graph.microsoft.com/v1.0/";
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[MSGraphBaseURL stringByAppendingString:@"/me/messages/AAMkADI5MAAIT3drCAAA=/attachments/createUploadSession"]]];
[urlRequest setHTTPMethod:@"POST"];
[urlRequest setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
NSMutableDictionary *payloadDictionary = [[NSMutableDictionary alloc] init];
MSGraphAttachmentItem *attachmentItem = [[MSGraphAttachmentItem alloc] init];
[attachmentItem setAttachmentType: [MSGraphAttachmentType file]];
[attachmentItem setName:@"flower"];
[attachmentItem setSize: 3483322];
payloadDictionary[@"AttachmentItem"] = attachmentItem;
NSData *data = [NSJSONSerialization dataWithJSONObject:payloadDictionary options:kNilOptions error:&error];
[urlRequest setHTTPBody:data];
MSURLSessionDataTask *meDataTask = [httpClient dataTaskWithRequest:urlRequest
completionHandler: ^(NSData *data, NSURLResponse *response, NSError *nserror) {
//Request Completed
}];
[meDataTask execute];
阅读 SDK 文档 ,详细了解如何将 SDK 添加到项目并创建 authProvider 实例。
IGraphServiceClient graphClient = GraphServiceClient.builder().authenticationProvider( authProvider ).buildClient();
AttachmentItem attachmentItem = new AttachmentItem();
attachmentItem.attachmentType = AttachmentType.FILE;
attachmentItem.name = "flower";
attachmentItem.size = 3483322;
graphClient.me().messages("AAMkADI5MAAIT3drCAAA=").attachments()
.createUploadSession(attachmentItem)
.buildRequest()
.post();
阅读 SDK 文档 ,详细了解如何将 SDK 添加到项目并创建 authProvider 实例。
响应
下列示例响应显示为邮件返回的 uploadSession 资源。
HTTP/1.1 201 Created
Content-type: application/json
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#microsoft.graph.uploadSession",
"uploadUrl": "https://outlook.office.com/api/v2.0/Users('a8e8e219-4931-95c1-b73d-62626fd79c32@72aa88bf-76f0-494f-91ab-2d7cd730db47')/Messages('AAMkADI5MAAIT3drCAAA=')/AttachmentSessions('AAMkADI5MAAIT3k0tAAA=')?authtoken=eyJhbGciOiJSUzI1NiIsImtpZCI6IktmYUNIUlN6bllHMmNI",
"expirationDateTime": "2019-09-25T01:09:30.7671707Z",
"nextExpectedRanges": [
"0-"
]
}
示例:创建事件的上传会话
请求
POST https://graph.microsoft.com/v1.0/me/events/AAMkADU5CCmSAAA=/attachments/createUploadSession
Content-type: application/json
{
"AttachmentItem": {
"attachmentType": "file",
"name": "flower",
"size": 3483322
}
}
GraphServiceClient graphClient = new GraphServiceClient( authProvider );
var attachmentItem = new AttachmentItem
{
AttachmentType = AttachmentType.File,
Name = "flower",
Size = 3483322
};
await graphClient.Me.Events["AAMkADU5CCmSAAA="].Attachments
.CreateUploadSession(attachmentItem)
.Request()
.PostAsync();
阅读 SDK 文档 ,详细了解如何将 SDK 添加到项目并创建 authProvider 实例。
const options = {
authProvider,
};
const client = Client.init(options);
const uploadSession = {
AttachmentItem: {
attachmentType: "file",
name: "flower",
size: 3483322
}
};
let res = await client.api('/me/events/AAMkADU5CCmSAAA=/attachments/createUploadSession')
.post(uploadSession);
阅读 SDK 文档 ,详细了解如何将 SDK 添加到项目并创建 authProvider 实例。
MSHTTPClient *httpClient = [MSClientFactory createHTTPClientWithAuthenticationProvider:authenticationProvider];
NSString *MSGraphBaseURL = @"https://graph.microsoft.com/v1.0/";
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[MSGraphBaseURL stringByAppendingString:@"/me/events/AAMkADU5CCmSAAA=/attachments/createUploadSession"]]];
[urlRequest setHTTPMethod:@"POST"];
[urlRequest setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
NSMutableDictionary *payloadDictionary = [[NSMutableDictionary alloc] init];
MSGraphAttachmentItem *attachmentItem = [[MSGraphAttachmentItem alloc] init];
[attachmentItem setAttachmentType: [MSGraphAttachmentType file]];
[attachmentItem setName:@"flower"];
[attachmentItem setSize: 3483322];
payloadDictionary[@"AttachmentItem"] = attachmentItem;
NSData *data = [NSJSONSerialization dataWithJSONObject:payloadDictionary options:kNilOptions error:&error];
[urlRequest setHTTPBody:data];
MSURLSessionDataTask *meDataTask = [httpClient dataTaskWithRequest:urlRequest
completionHandler: ^(NSData *data, NSURLResponse *response, NSError *nserror) {
//Request Completed
}];
[meDataTask execute];
阅读 SDK 文档 ,详细了解如何将 SDK 添加到项目并创建 authProvider 实例。
IGraphServiceClient graphClient = GraphServiceClient.builder().authenticationProvider( authProvider ).buildClient();
AttachmentItem attachmentItem = new AttachmentItem();
attachmentItem.attachmentType = AttachmentType.FILE;
attachmentItem.name = "flower";
attachmentItem.size = 3483322;
graphClient.me().events("AAMkADU5CCmSAAA=").attachments()
.createUploadSession(attachmentItem)
.buildRequest()
.post();
阅读 SDK 文档 ,详细了解如何将 SDK 添加到项目并创建 authProvider 实例。
响应
下列示例响应显示为shi'jian事件返回的 uploadSession 资源。
HTTP/1.1 201 Created
Content-type: application/json
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#microsoft.graph.uploadSession",
"uploadUrl": "https://outlook.office.com/api/v2.0/Users('d3b9214b-dd8b-441d-b7dc-c446c9fa0e69@98a79ebe-74bf-4e07-a017-7b410848cb32')/Events('AAMkADU5CCmSAAA=')/AttachmentSessions('AAMkADU5RpAACJlCs8AAA=')?authtoken=eyJhbGciOiJSUzI1NiIsImtpZCI6IktmYUNIBtw",
"expirationDateTime": "2020-02-22T02:46:56.7410786Z",
"nextExpectedRanges": [
"0-"
]
}
步骤 2:使用上传会话上传文件的字节范围
如果要上传文件或文件的一部分,在 uploadSession 资源 uploadUrl 属性中,对第 1 步返回的 URL 进行 PUT 请求。 可上传整个文件,或将文件拆分为多个字节范围。 为获得更好的性能,请保持每个字节范围小于 4 MB。
按如下所述指定请求标头和请求正文。
请求标头
名称
类型
说明
Content-Length
Int32
此操作中上传的字节数。 为获得更好的性能,请将每个 PUT 操作的字节数的上限限制为 4 MB。 必填。
Content-Range
字符串
此操作中要上传的文件的从 0 开始的字节范围,格式为 bytes {start}-{end}/{total}。 必填。
Content-Type
String
MIME 类型。 指定 application/octet-stream。 必填。
请勿指定 Authorization 请求标头。 PUT 查询使用 uploadUrl 属性中预身份验证的 URL,该属性允许访问 https://outlook.office.com 域。
请求正文
指定要附加的文件的实际字节数,它们位于由 Content-Range 请求标头指定的位置范围内。
响应
成功的上传将返回 HTTP 200 OK 和 uploadSession 对象。 请注意响应对象中的以下项:
ExpirationDateTime 属性指示 uploadUrl 属性值中嵌入的身份验证令牌的到期日期/时间。 此到期日期/时间与步骤 1 中由初始 uploadSession 返回的值相同。
NextExpectedRanges 指定上传开始的下一个字节位置,例如 "NextExpectedRanges":["2097152"]。 必须按顺序上传文件中的字节。
uploadUrl 属性不会显式返回,因为上传会话的所有 PUT 操作使用创建会话时返回的同一 URL(步骤 1)。
示例:首先上传至消息
请求
PUT https://outlook.office.com/api/v2.0/Users('a8e8e219-4931-95c1-b73d-62626fd79c32@72aa88bf-76f0-494f-91ab-2d7cd730db47')/Messages('AAMkADI5MAAIT3drCAAA=')/AttachmentSessions('AAMkADI5MAAIT3k0tAAA=')?authtoken=eyJhbGciOiJSUzI1NiIsImtpZCI6IktmYUNIUlN6bllHMmNI
Content-Type: application/octet-stream
Content-Length: 2097152
Content-Range: bytes 0-2097151/3483322
{
}
响应
下列示例响应在 NextExpectedRanges 属性中显示服务器预期的下一字节范围的起点。
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":"https://outlook.office.com/api/v2.0/$metadata#Users('a8e8e219-4931-95c1-b73d-62626fd79c32%4072aa88bf-76f0-494f-91ab-2d7cd730db47')/Messages('AAMkADI5MAAIT3drCAAA%3D')/AttachmentSessions/$entity",
"ExpirationDateTime":"2019-09-25T01:09:30.7671707Z",
"NextExpectedRanges":["2097152"]
}
示例:首先上传至事件
请求
PUT https://outlook.office.com/api/v2.0/Users('d3b9214b-dd8b-441d-b7dc-c446c9fa0e69@98a79ebe-74bf-4e07-a017-7b410848cb32')/Events('AAMkADU5CCmSAAA=')/AttachmentSessions('AAMkADU5RpAACJlCs8AAA=')?authtoken=eyJhbGciOiJSUzI1NiIsImtpZCI6IktmYUNIBtw
Content-Type: application/octet-stream
Content-Length: 2097152
Content-Range: bytes 0-2097151/3483322
{
}
响应
下列示例响应在 NextExpectedRanges 属性中显示服务器预期的下一字节范围的起点。
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context":"https://outlook.office.com/api/v2.0/$metadata#Users('d3b9214b-dd8b-441d-b7dc-c446c9fa0e69%4098a79ebe-74bf-4e07-a017-7b410848cb32')/Events('AAMkADU5CCmSAAA%3D')/AttachmentSessions/$entity",
"ExpirationDateTime":"2020-02-22T02:46:56.7410786Z",
"NextExpectedRanges":["2097152"]
}
步骤 3:继续上传字节范围,直至完整文件上传完毕
执行步骤 2 中的初始上传后,在会话的到期日期/时间前,使用步骤 2 中所述的 PUT 请求,继续上传文件中剩余的部分。 使用 NextExpectedRanges 集合确定要上传的下一个字节范围的开头。 可能会发现指定了多个范围,这些范围指明了服务器尚未收到的文件部分。 如果需要恢复中断的传输,并且客户端不能确定服务的状态,这个方法很有用。
成功上传文件的最后一个字节后,最终 PUT 操作返回 HTTP 201 Created 以及指示 https://outlook.office.com 域中文件附件 URL 的 Location 标头。 可从 URL 获取附件 ID 并将其保存供以后使用。 可以使用该 ID 获取附件的元数据,或使用 Microsoft Graph 终结点将附件从 Outlook 项中删除,具体取决于你的场景。
下列示例显示在此处理步骤中上传最后的文件字节范围至邮件和事件。
示例:最后上传至消息
请求
PUT https://outlook.office.com/api/v2.0/Users('a8e8e219-4931-95c1-b73d-62626fd79c32@72aa88bf-76f0-494f-91ab-2d7cd730db47')/Messages('AAMkADI5MAAIT3drCAAA=')/AttachmentSessions('AAMkADI5MAAIT3k0tAAA=')?authtoken=eyJhbGciOiJSUzI1NiIsImtpZCI6IktmYUNIUlN6bllHMmNI
Content-Type: application/octet-stream
Content-Length: 1386170
Content-Range: bytes 2097152-3483321/3483322
{
}
响应
下列示例显示可保存附件 ID(AAMkADI5MAAIT3drCAAABEgAQANAqbAe7qaROhYdTnUQwXm0=)以供随后使用的 Location 响应标头。
HTTP/1.1 201 Created
Location: https://outlook.office.com/api/v2.0/Users('a8e8e219-4931-95c1-b73d-62626fd79c32@72aa88bf-76f0-494f-91ab-2d7cd730db47')/Messages('AAMkADI5MAAIT3drCAAA=')/Attachments('AAMkADI5MAAIT3drCAAABEgAQANAqbAe7qaROhYdTnUQwXm0=')
Content-Length: 0
示例:最后上传至事件
请求
PUT https://outlook.office.com/api/v2.0/Users('d3b9214b-dd8b-441d-b7dc-c446c9fa0e69@98a79ebe-74bf-4e07-a017-7b410848cb32')/Events('AAMkADU5CCmSAAA=')/AttachmentSessions('AAMkADU5RpAACJlCs8AAA=')?authtoken=eyJhbGciOiJSUzI1NiIsImtpZCI6IktmYUNIBtw
Content-Type: application/octet-stream
Content-Length: 1386170
Content-Range: bytes 2097152-3483321/3483322
{
}
响应
下列示例显示可保存附件 ID(AAMkADU5CCmSAAANZAlYPeyQByv7Y=)以供随后使用的 Location 响应标头。
HTTP/1.1 201 Created
Location: https://outlook.office.com/api/v2.0/Users('d3b9214b-dd8b-441d-b7dc-c446c9fa0e69@98a79ebe-74bf-4e07-a017-7b410848cb32')/Events('AAMkADU5CCmSAAA=')/Attachments('AAMkADU5CCmSAAANZAlYPeyQByv7Y=')
Content-Length: 0
步骤 4(可选):从 Outlook 项中获取文件附件
和往常一样,从 Outlook 项中获取附件在理论上并不受附件大小限制。
但是,获取采用 base64 编码格式的大文件附件会影响 API 性能。 如果需要大型附件:
作为获取采用 base64 格式的附件内容的替代方法,可以获取文件附件的元数据。
要 获取文件附件的元数据,可以附加 $select 参数以仅包含所需的元数据属性,排除返回采用 base64 格式的文件附件的 contentBytes 属性。
示例:获取附加到事件的原始文件
按照事件示例和使用 Location 上一步标头中返回的附件 ID,此部分中的示例请求显示了使用 $value 参数获取附件的原始内容数据。
权限
对此操作视情况使用权限最低的委派或应用程序权限,Calendars.Read。 有关详细信息,请参阅 日历权限。
请求
GET https://graph.microsoft.com/v1.0/Users('d3b9214b-dd8b-441d-b7dc-c446c9fa0e69@98a79ebe-74bf-4e07-a017-7b410848cb32')/Events('AAMkADU5CCmSAAA=')/Attachments('AAMkADU5CCmSAAANZAlYPeyQByv7Y=')/$value
响应
HTTP/1.1 200 OK
content-length: 3483322
Content-type: image/jpeg
{Raw bytes of the file}
示例:获取邮件附加的文件的元数据
按照邮件示例,此部分中的示例请求显示使用 $select 参数来获取有关邮件的文件附件的部分元数据,不包括 contentBytes。
权限
对此操作视情况使用权限最低的委派或应用程序权限,Mail.Read。 有关详细信息,请参阅 邮件权限。
请求
GET https://graph.microsoft.com/api/v1.0/Users('a8e8e219-4931-95c1-b73d-62626fd79c32@72aa88bf-76f0-494f-91ab-2d7cd730db47')/Messages('AAMkADI5MAAIT3drCAAA=')/Attachments('AAMkADI5MAAIT3drCAAABEgAQANAqbAe7qaROhYdTnUQwXm0=')?$select=lastModifiedDateTime,name,contentType,size,isInline
响应
HTTP/1.1 200 OK
Content-type: application/json
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users('a8e8e219-4931-95c1-b73d-62626fd79c32%4072aa88bf-76f0-494f-91ab-2d7cd730db47')/messages('AAMkADI5MAAIT3drCAAA%3D')/attachments/$entity",
"@odata.type": "#microsoft.graph.fileAttachment",
"@odata.mediaContentType": "image/jpeg",
"id": "AAMkADI5MAAIT3drCAAABEgAQANAqbAe7qaROhYdTnUQwXm0=",
"lastModifiedDateTime": "2019-09-24T23:27:43Z",
"name": "flower",
"contentType": "image/jpeg",
"size": 3640066,
"isInline": false
}
替代方法:取消上传会话
在上传会话到期之前的任何时间,如果必须取消上传,可使用同一初始非跳转 URL 来删除上传会话。 成功的操作将返回 HTTP 204 No Content。
权限
由于初始不透明的 URL 为预验证,并包含该上传会话后续查询的适当授权令牌,所以请勿为此操作指定授权请求标题。
示例:取消邮件的上传会话
请求
DELETE https://outlook.office.com/api/v2.0/Users('a8e8e219-4931-95c1-b73d-62626fd79c32@72aa88bf-76f0-494f-91ab-2d7cd730db47')/Messages('AAMkADI5MAAIT3drCAAA=')/AttachmentSessions('AAMkADI5MAAIT3k0tAAA=')?authtoken=eyJhbGciOiJSUzI1NiIsImtpZCI6IktmYUNIUlN6bllHMmNI
响应
HTTP/1.1 204 No content
错误
ErrorAttachmentSizeShouldNotBeLessThanMinimumSize
尝试创建上传会话以附加小于 3 MB 的文件时返回此错误。 如果文件大小小于 3 MB,则应该针对 邮件或 事件的 附件 导航属性执行单个 POST。 成功的 POST 响应包括附加到邮件的文件的 ID。