feat(outlook): implement retrieve_outlook_raw_email to fetch and save EML via Graph API

This commit is contained in:
rustmailer
2025-11-05 09:55:49 +08:00
parent b9534b2a1c
commit c2ec7e869f
12 changed files with 238 additions and 101 deletions
+1 -1
View File
@@ -18,8 +18,8 @@ use crate::{
messages::{FullMessage, MessageList, MessageMeta, PartBody},
},
},
common::http::HttpClient,
error::{code::ErrorCode, RustMailerResult},
hook::http::HttpClient,
mailbox::{create::CreateMailboxRequest, rename::MailboxUpdateRequest},
message::append::ReplyDraft,
oauth2::token::OAuth2AccessToken,
+14 -1
View File
@@ -1,3 +1,4 @@
use bytes::Bytes;
use serde_json::json;
use crate::{
@@ -5,8 +6,8 @@ use crate::{
cache::vendor::outlook::model::{
MailFolder, MailFoldersResponse, Message, MessageListResponse,
},
common::http::HttpClient,
error::{code::ErrorCode, RustMailerResult},
hook::http::HttpClient,
message::append::ReplyDraft,
oauth2::token::OAuth2AccessToken,
},
@@ -230,6 +231,18 @@ impl OutlookClient {
Ok(message)
}
pub async fn get_raw_message(
account_id: u64,
use_proxy: Option<u64>,
id: &str,
) -> RustMailerResult<Bytes> {
let url = format!("https://graph.microsoft.com/v1.0/me/messages/{id}/$value");
let client = HttpClient::new(use_proxy).await?;
let access_token = Self::get_access_token(account_id).await?;
let value = client.get_bytes(url.as_str(), &access_token).await?;
Ok(value)
}
pub async fn get_attachment(
account_id: u64,
use_proxy: Option<u64>,
+6 -13
View File
@@ -7,24 +7,17 @@ use serde::{Deserialize, Serialize};
use crate::{
modules::{
account::migration::AccountModel,
cache::vendor::outlook::{
account::migration::AccountModel, cache::vendor::outlook::{
model::DeltaResponse,
sync::{client::OutlookClient, envelope::OutlookEnvelope, folders::OutlookFolder},
},
database::{
}, common::http::HttpClient, database::{
async_find_impl, batch_delete_impl, filter_by_secondary_key_impl, manager::DB_MANAGER,
upsert_impl,
},
error::{code::ErrorCode, RustMailerResult},
hook::{
channel::{Event, EVENT_CHANNEL},
events::{payload::EmailAddedToFolder, EventPayload, EventType, RustMailerEvent},
http::HttpClient,
}, error::{RustMailerResult, code::ErrorCode}, hook::{
channel::{EVENT_CHANNEL, Event},
events::{EventPayload, EventType, RustMailerEvent, payload::EmailAddedToFolder},
task::EventHookTask,
},
message::content::FullMessageContent,
utils::mailbox_id,
}, message::content::FullMessageContent, utils::mailbox_id
},
raise_error, utc_now,
};
+36 -6
View File
@@ -2,21 +2,18 @@
// Licensed under RustMailer License Agreement v1.0
// Unauthorized copying, modification, or distribution is prohibited.
use http::header::CONTENT_TYPE;
use http::header::{ACCEPT, CONTENT_TYPE};
use poem_grpc::{ClientConfig, CompressionEncoding};
use reqwest::{header::AUTHORIZATION, Client};
use std::{future::Future, pin::Pin, time::Duration};
use std::{fs::File, future::Future, io::Write, pin::Pin, time::Duration};
use crate::{
modules::{
cache::vendor::outlook::model::{
MailFolder, MailFoldersResponse, Message, MessageListResponse,
},
cache::vendor::outlook::model::{MailFolder, MailFoldersResponse, MessageListResponse},
common::rustls::RustMailerTls,
context::Initialize,
error::{code::ErrorCode, RustMailerResult},
grpc::service::rustmailer_grpc::{GetOAuth2TokensRequest, OAuth2ServiceClient},
hook::http::HttpClient,
},
raise_error, rustmailer_version,
};
@@ -488,3 +485,36 @@ async fn create_reply_draft() {
eprintln!("Error: {} - {:?}", res.status(), res.text().await.unwrap());
}
}
#[tokio::test]
async fn get_raw_message() {
let access_token = access_token().await;
let url = format!(
"https://graph.microsoft.com/v1.0/me/messages/{}/$value",
"AQMkADAwATMwMAItNzE0OC1jZTEzLTAwAi0wMAoARgAAA_KUk7xWPSBEntPHShr61lgHAOo9V4GwHndCjf0x1uoIcwUAAAIBDAAAAOo9V4GwHndCjf0x1uoIcwUAAYiJVIEAAAA="
);
let client = reqwest::Client::builder()
.user_agent(rustmailer_version!())
.timeout(Duration::from_secs(10))
.connect_timeout(Duration::from_secs(10))
.proxy(reqwest::Proxy::all("http://127.0.0.1:22307").unwrap())
.redirect(reqwest::redirect::Policy::none())
.build()
.unwrap();
let res = client
.get(&url)
.header(AUTHORIZATION, format!("Bearer {}", access_token))
.header(ACCEPT, "application/octet-stream")
.send()
.await
.unwrap();
if res.status().is_success() {
let bytes = res.bytes().await.unwrap();
let mut file = File::create("e:\\message.eml").unwrap();
file.write_all(&bytes).unwrap();
} else {
eprintln!("Error: {} - {:?}", res.status(), res.text().await.unwrap());
}
}