mirror of
https://github.com/rustmailer/rustmailer.git
synced 2026-09-09 00:01:34 +00:00
feat(thread): Add support for fetching thread lists and thread messages from remote in Gmail and Graph API
This commit is contained in:
+374
-67
@@ -10,7 +10,10 @@ use crate::{
|
||||
imap::{mailbox::MailBox, migration::EmailEnvelopeV3, thread::EmailThread},
|
||||
model::Envelope,
|
||||
vendor::{
|
||||
gmail::sync::{client::GmailClient, envelope::GmailEnvelope, labels::GmailLabels},
|
||||
gmail::{
|
||||
model::thread::{get_thread_messages_impl, list_threads_impl},
|
||||
sync::{client::GmailClient, envelope::GmailEnvelope, labels::GmailLabels},
|
||||
},
|
||||
outlook::sync::{
|
||||
client::OutlookClient, envelope::OutlookEnvelope, folders::OutlookFolder,
|
||||
},
|
||||
@@ -42,9 +45,9 @@ pub async fn list_messages_in_mailbox(
|
||||
ErrorCode::InvalidParameter
|
||||
));
|
||||
}
|
||||
if page_size > 500 {
|
||||
if page_size > 100 {
|
||||
return Err(raise_error!(
|
||||
"The page_size exceeds the maximum allowed limit of 500.".into(),
|
||||
"The page_size exceeds the maximum allowed limit of 100.".into(),
|
||||
ErrorCode::InvalidParameter
|
||||
));
|
||||
}
|
||||
@@ -56,21 +59,21 @@ pub async fn list_messages_in_mailbox(
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_pagination_params(page: u64, page_size: u64) -> RustMailerResult<()> {
|
||||
if page == 0 || page_size == 0 {
|
||||
return Err(raise_error!(
|
||||
"Both page and page_size must be greater than 0.".into(),
|
||||
ErrorCode::InvalidParameter
|
||||
));
|
||||
}
|
||||
if page_size > 500 {
|
||||
return Err(raise_error!(
|
||||
"The page_size exceeds the maximum allowed limit of 500.".into(),
|
||||
ErrorCode::InvalidParameter
|
||||
));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
// fn validate_pagination_params(page: u64, page_size: u64) -> RustMailerResult<()> {
|
||||
// if page == 0 || page_size == 0 {
|
||||
// return Err(raise_error!(
|
||||
// "Both page and page_size must be greater than 0.".into(),
|
||||
// ErrorCode::InvalidParameter
|
||||
// ));
|
||||
// }
|
||||
// if page_size > 500 {
|
||||
// return Err(raise_error!(
|
||||
// "The page_size exceeds the maximum allowed limit of 500.".into(),
|
||||
// ErrorCode::InvalidParameter
|
||||
// ));
|
||||
// }
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
async fn fetch_remote_messages(
|
||||
account: &AccountModel,
|
||||
@@ -79,6 +82,12 @@ async fn fetch_remote_messages(
|
||||
page_size: u64,
|
||||
desc: bool,
|
||||
) -> RustMailerResult<CursorDataPage<Envelope>> {
|
||||
if page_size > 100 {
|
||||
return Err(raise_error!(
|
||||
"The page_size exceeds the maximum allowed limit of 100.".into(),
|
||||
ErrorCode::InvalidParameter
|
||||
));
|
||||
}
|
||||
match account.mailer_type {
|
||||
MailerType::ImapSmtp => {
|
||||
let page = decode_page_token(next_page_token)?;
|
||||
@@ -125,7 +134,7 @@ async fn fetch_remote_messages(
|
||||
}
|
||||
MailerType::GmailApi => {
|
||||
let label_map =
|
||||
GmailClient::reverse_label_map(account.id, account.use_proxy, true).await?;
|
||||
GmailClient::for_lookup_label_id(account.id, account.use_proxy, true).await?;
|
||||
let label_id = label_map.get(mailbox_name).ok_or_else(|| {
|
||||
raise_error!(
|
||||
format!("Label not found for mailbox: {}", mailbox_name),
|
||||
@@ -135,7 +144,7 @@ async fn fetch_remote_messages(
|
||||
let message_list = GmailClient::list_messages(
|
||||
account.id,
|
||||
account.use_proxy,
|
||||
label_id,
|
||||
Some(label_id),
|
||||
next_page_token,
|
||||
None,
|
||||
page_size as u32,
|
||||
@@ -171,7 +180,7 @@ async fn fetch_remote_messages(
|
||||
GmailClient::get_message(account_id, use_proxy, &index.id).await
|
||||
})
|
||||
.await?;
|
||||
|
||||
let label_map = GmailClient::for_get_label_name(account.id, account.use_proxy).await?;
|
||||
let envelopes: Vec<Envelope> = batch_messages
|
||||
.into_iter()
|
||||
.map(|m| {
|
||||
@@ -197,10 +206,21 @@ async fn fetch_remote_messages(
|
||||
let folder = folders
|
||||
.into_iter()
|
||||
.find(|f| f.display_name == mailbox_name)
|
||||
.ok_or_else(|| raise_error!("".into(), ErrorCode::InvalidParameter))?;
|
||||
let total_items = folder
|
||||
.total_item_count
|
||||
.ok_or_else(|| raise_error!("".into(), ErrorCode::InvalidParameter))?;
|
||||
.ok_or_else(|| {
|
||||
raise_error!(
|
||||
format!("Outlook folder '{}' not found.", mailbox_name),
|
||||
ErrorCode::InvalidParameter
|
||||
)
|
||||
})?;
|
||||
let total_items = folder.total_item_count.ok_or_else(|| {
|
||||
raise_error!(
|
||||
format!(
|
||||
"Outlook folder '{}' does not provide 'total_item_count'.",
|
||||
mailbox_name
|
||||
),
|
||||
ErrorCode::InvalidParameter
|
||||
)
|
||||
})?;
|
||||
|
||||
if total_items == 0 {
|
||||
return Ok(CursorDataPage::new(
|
||||
@@ -224,7 +244,7 @@ async fn fetch_remote_messages(
|
||||
)
|
||||
.await?;
|
||||
|
||||
let envelopes: Vec<OutlookEnvelope> = resp
|
||||
let envelopes: Vec<Envelope> = resp
|
||||
.value
|
||||
.into_iter()
|
||||
.map(|m| {
|
||||
@@ -232,9 +252,12 @@ async fn fetch_remote_messages(
|
||||
envelope.account_id = account.id;
|
||||
envelope.folder_id = mailbox_id(account.id, &folder.id);
|
||||
envelope.folder_name = mailbox_name.to_string();
|
||||
Ok(envelope)
|
||||
let conversation_id = envelope.conversation_id.clone();
|
||||
let mut e = Envelope::from(envelope);
|
||||
e.thread_id = conversation_id.unwrap_or("unknown".into());
|
||||
Ok(e)
|
||||
})
|
||||
.collect::<RustMailerResult<Vec<OutlookEnvelope>>>()?;
|
||||
.collect::<RustMailerResult<Vec<Envelope>>>()?;
|
||||
|
||||
let next_page_token = if page == total_pages {
|
||||
None
|
||||
@@ -247,7 +270,7 @@ async fn fetch_remote_messages(
|
||||
Some(page_size),
|
||||
total_items as u64,
|
||||
Some(total_pages),
|
||||
envelopes.into_iter().map(Into::into).collect(),
|
||||
envelopes,
|
||||
))
|
||||
}
|
||||
}
|
||||
@@ -328,7 +351,7 @@ async fn fetch_local_messages(
|
||||
total_pages,
|
||||
} = GmailEnvelope::list_messages_in_label(target_label.id, page, page_size, desc)
|
||||
.await?;
|
||||
let map = GmailClient::label_map(account.id, account.use_proxy).await?;
|
||||
let map = GmailClient::for_get_label_name(account.id, account.use_proxy).await?;
|
||||
|
||||
if total_items == 0 {
|
||||
Ok(CursorDataPage::new(None, page_size, 0, None, vec![]))
|
||||
@@ -398,21 +421,22 @@ async fn fetch_local_messages(
|
||||
pub async fn list_threads_in_mailbox(
|
||||
account_id: u64,
|
||||
mailbox_name: &str,
|
||||
page: u64,
|
||||
next_page_token: Option<&str>,
|
||||
page_size: u64,
|
||||
remote: bool,
|
||||
desc: bool,
|
||||
) -> RustMailerResult<DataPage<Envelope>> {
|
||||
) -> RustMailerResult<CursorDataPage<Envelope>> {
|
||||
let account = AccountModel::check_account_active(account_id, false).await?;
|
||||
validate_pagination_params(page, page_size)?;
|
||||
if account.minimal_sync() {
|
||||
if page_size == 0 {
|
||||
return Err(raise_error!(
|
||||
format!(
|
||||
"Account {} is in minimal sync mode. Listing threads in a mailbox is not supported. \
|
||||
To enable this feature, you must delete the email account configuration and set it up again \
|
||||
with minimal sync mode disabled.",
|
||||
account_id
|
||||
),
|
||||
ErrorCode::Incompatible
|
||||
"page_size must be greater than 0.".into(),
|
||||
ErrorCode::InvalidParameter
|
||||
));
|
||||
}
|
||||
if page_size > 100 {
|
||||
return Err(raise_error!(
|
||||
"The page_size exceeds the maximum allowed limit of 100.".into(),
|
||||
ErrorCode::InvalidParameter
|
||||
));
|
||||
}
|
||||
|
||||
@@ -430,52 +454,335 @@ pub async fn list_threads_in_mailbox(
|
||||
|
||||
match account.mailer_type {
|
||||
MailerType::ImapSmtp => {
|
||||
if account.minimal_sync() {
|
||||
return Err(raise_error!(
|
||||
format!(
|
||||
"Account {} is configured with minimal_sync. RustMailer does not sync the required \
|
||||
metadata for IMAP accounts in this mode, so thread information cannot be obtained. \
|
||||
IMAP servers do not provide native thread data, therefore you must recreate the \
|
||||
account without minimal_sync to enable thread listing.",
|
||||
account_id
|
||||
),
|
||||
ErrorCode::Incompatible
|
||||
));
|
||||
}
|
||||
|
||||
if remote {
|
||||
return Err(raise_error!(
|
||||
format!(
|
||||
"IMAP accounts cannot use the 'remote' parameter because thread lists cannot be \
|
||||
retrieved directly from an IMAP server. The IMAP protocol does not provide any \
|
||||
native thread information, so remote thread listing is unsupported.",
|
||||
),
|
||||
ErrorCode::Incompatible
|
||||
));
|
||||
}
|
||||
|
||||
let page = decode_page_token(next_page_token)?;
|
||||
let mailbox = MailBox::get(account.id, mailbox_name)
|
||||
.await
|
||||
.map_err(|_| not_found_err())?;
|
||||
EmailThread::list_threads_in_mailbox(mailbox.id, page, page_size, desc).await
|
||||
let DataPage {
|
||||
current_page: _,
|
||||
page_size,
|
||||
total_items,
|
||||
items,
|
||||
total_pages,
|
||||
} = EmailThread::list_threads_in_mailbox(mailbox.id, page, page_size, desc).await?;
|
||||
|
||||
if total_items == 0 {
|
||||
Ok(CursorDataPage::new(None, page_size, 0, None, vec![]))
|
||||
} else {
|
||||
let total_pages = total_pages.ok_or_else(|| {
|
||||
raise_error!(
|
||||
"Internal error: total_pages is None (this should never happen)".into(),
|
||||
ErrorCode::InternalError
|
||||
)
|
||||
})?;
|
||||
|
||||
let next_page_token = if page == total_pages {
|
||||
None
|
||||
} else {
|
||||
Some(base64_encode_url_safe!((page + 1).to_string()))
|
||||
};
|
||||
|
||||
Ok(CursorDataPage::new(
|
||||
next_page_token,
|
||||
page_size,
|
||||
total_items,
|
||||
Some(total_pages),
|
||||
items,
|
||||
))
|
||||
}
|
||||
}
|
||||
MailerType::GmailApi => {
|
||||
let label = GmailLabels::get_by_name(account_id, mailbox_name).await?;
|
||||
EmailThread::list_threads_in_label(account, label.id, page, page_size, desc).await
|
||||
if account.minimal_sync() || remote {
|
||||
let label_map =
|
||||
GmailClient::for_lookup_label_id(account.id, account.use_proxy, true).await?;
|
||||
let label_id = label_map.get(mailbox_name).ok_or_else(|| {
|
||||
raise_error!(
|
||||
format!("Label not found for mailbox: {}", mailbox_name),
|
||||
ErrorCode::ResourceNotFound
|
||||
)
|
||||
})?;
|
||||
|
||||
list_threads_impl(
|
||||
account_id,
|
||||
account.use_proxy,
|
||||
Some(label_id),
|
||||
next_page_token,
|
||||
None,
|
||||
page_size,
|
||||
)
|
||||
.await
|
||||
} else {
|
||||
let page = decode_page_token(next_page_token)?;
|
||||
let label = GmailLabels::get_by_name(account_id, mailbox_name).await?;
|
||||
let DataPage {
|
||||
current_page: _,
|
||||
page_size,
|
||||
total_items,
|
||||
items,
|
||||
total_pages,
|
||||
} = EmailThread::list_threads_in_label(account, label.id, page, page_size, desc)
|
||||
.await?;
|
||||
|
||||
if total_items == 0 {
|
||||
Ok(CursorDataPage::new(None, page_size, 0, None, vec![]))
|
||||
} else {
|
||||
let total_pages = total_pages.ok_or_else(|| {
|
||||
raise_error!(
|
||||
"Internal error: total_pages is None (this should never happen)".into(),
|
||||
ErrorCode::InternalError
|
||||
)
|
||||
})?;
|
||||
|
||||
let next_page_token = if page == total_pages {
|
||||
None
|
||||
} else {
|
||||
Some(base64_encode_url_safe!((page + 1).to_string()))
|
||||
};
|
||||
|
||||
Ok(CursorDataPage::new(
|
||||
next_page_token,
|
||||
page_size,
|
||||
total_items,
|
||||
Some(total_pages),
|
||||
items,
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
MailerType::GraphApi => {
|
||||
let folder = OutlookFolder::get_by_name(account_id, mailbox_name).await?;
|
||||
EmailThread::list_threads_in_folder(folder.id, page, page_size, desc).await
|
||||
let page = decode_page_token(next_page_token)?;
|
||||
if account.minimal_sync() || remote {
|
||||
let folders =
|
||||
OutlookClient::list_mailfolders(account.id, account.use_proxy).await?;
|
||||
let folder = folders
|
||||
.into_iter()
|
||||
.find(|f| f.display_name == mailbox_name)
|
||||
.ok_or_else(|| {
|
||||
raise_error!(
|
||||
format!("Outlook folder '{}' not found.", mailbox_name),
|
||||
ErrorCode::InvalidParameter
|
||||
)
|
||||
})?;
|
||||
let total_items = folder.total_item_count.ok_or_else(|| {
|
||||
raise_error!(
|
||||
format!(
|
||||
"Outlook folder '{}' does not provide 'total_item_count'.",
|
||||
mailbox_name
|
||||
),
|
||||
ErrorCode::InvalidParameter
|
||||
)
|
||||
})?;
|
||||
|
||||
if total_items == 0 {
|
||||
return Ok(CursorDataPage::new(
|
||||
None,
|
||||
Some(page_size),
|
||||
0,
|
||||
Some(0),
|
||||
vec![],
|
||||
));
|
||||
}
|
||||
|
||||
let total_pages = (total_items as f64 / page_size as f64).ceil() as u64;
|
||||
let resp = OutlookClient::list_messages(
|
||||
account.id,
|
||||
account.use_proxy,
|
||||
&folder.id,
|
||||
page,
|
||||
page_size,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let envelopes: Vec<Envelope> = resp
|
||||
.value
|
||||
.into_iter()
|
||||
.map(|m| {
|
||||
let mut envelope: OutlookEnvelope = m.try_into()?;
|
||||
envelope.account_id = account.id;
|
||||
envelope.folder_id = mailbox_id(account.id, &folder.id);
|
||||
envelope.folder_name = mailbox_name.to_string();
|
||||
let conversation_id = envelope.conversation_id.clone();
|
||||
let mut e = Envelope::from(envelope);
|
||||
e.thread_id = conversation_id.unwrap_or("unknown".into());
|
||||
Ok(e)
|
||||
})
|
||||
.collect::<RustMailerResult<Vec<Envelope>>>()?;
|
||||
|
||||
let next_page_token = if page == total_pages {
|
||||
None
|
||||
} else {
|
||||
Some(base64_encode_url_safe!((page + 1).to_string()))
|
||||
};
|
||||
|
||||
Ok(CursorDataPage::new(
|
||||
next_page_token,
|
||||
Some(page_size),
|
||||
total_items as u64,
|
||||
Some(total_pages),
|
||||
envelopes,
|
||||
))
|
||||
} else {
|
||||
let folder = OutlookFolder::get_by_name(account_id, mailbox_name).await?;
|
||||
let DataPage {
|
||||
current_page: _,
|
||||
page_size,
|
||||
total_items,
|
||||
items,
|
||||
total_pages,
|
||||
} = EmailThread::list_threads_in_folder(folder.id, page, page_size, desc).await?;
|
||||
if total_items == 0 {
|
||||
Ok(CursorDataPage::new(None, page_size, 0, None, vec![]))
|
||||
} else {
|
||||
let total_pages = total_pages.ok_or_else(|| {
|
||||
raise_error!(
|
||||
"Internal error: total_pages is None (this should never happen)".into(),
|
||||
ErrorCode::InternalError
|
||||
)
|
||||
})?;
|
||||
|
||||
let next_page_token = if page == total_pages {
|
||||
None
|
||||
} else {
|
||||
Some(base64_encode_url_safe!((page + 1).to_string()))
|
||||
};
|
||||
|
||||
Ok(CursorDataPage::new(
|
||||
next_page_token,
|
||||
page_size,
|
||||
total_items,
|
||||
Some(total_pages),
|
||||
items,
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_thread_messages(
|
||||
account_id: u64,
|
||||
thread_id: u64,
|
||||
thread_id: String,
|
||||
remote: bool,
|
||||
) -> RustMailerResult<Vec<Envelope>> {
|
||||
let account = AccountModel::check_account_active(account_id, false).await?;
|
||||
if account.minimal_sync() {
|
||||
return Err(raise_error!(
|
||||
format!(
|
||||
"Account {} is in minimal sync mode. Listing threads in a mailbox is not supported. \
|
||||
To enable this feature, you must delete the email account configuration and set it up again \
|
||||
with minimal sync mode disabled.",
|
||||
account_id
|
||||
),
|
||||
ErrorCode::Incompatible
|
||||
));
|
||||
}
|
||||
|
||||
match account.mailer_type {
|
||||
MailerType::ImapSmtp => EmailEnvelopeV3::get_thread(account_id, thread_id).await,
|
||||
MailerType::ImapSmtp => {
|
||||
if account.minimal_sync() {
|
||||
return Err(raise_error!(
|
||||
format!(
|
||||
"Account {} is currently using minimal sync mode. IMAP accounts cannot provide thread \
|
||||
information when minimal sync is enabled because IMAP servers do not supply thread IDs. \
|
||||
Thread data must be computed locally, which requires full metadata caching. \
|
||||
To use thread-related features, please delete and re-add the email account with minimal sync disabled.",
|
||||
account_id
|
||||
),
|
||||
ErrorCode::Incompatible
|
||||
));
|
||||
}
|
||||
|
||||
if remote {
|
||||
return Err(raise_error!(
|
||||
format!(
|
||||
"IMAP accounts cannot use the 'remote' parameter because thread messages cannot be \
|
||||
retrieved directly from an IMAP server. The IMAP protocol does not provide any \
|
||||
native thread information, so get remote thread messages is unsupported.",
|
||||
),
|
||||
ErrorCode::Incompatible
|
||||
));
|
||||
}
|
||||
|
||||
let thread_id_num: u64 = thread_id.parse().map_err(|_| {
|
||||
raise_error!(
|
||||
format!(
|
||||
"Invalid thread_id: '{}'. IMAP thread_id must be a numeric string that can be parsed into a number.",
|
||||
thread_id
|
||||
),
|
||||
ErrorCode::InvalidParameter
|
||||
)
|
||||
})?;
|
||||
|
||||
EmailEnvelopeV3::get_thread(account_id, thread_id_num).await
|
||||
}
|
||||
MailerType::GmailApi => {
|
||||
let envelopes = GmailEnvelope::get_thread(account_id, thread_id).await?;
|
||||
let map = GmailClient::label_map(account_id, account.use_proxy).await?;
|
||||
Ok(envelopes
|
||||
.into_iter()
|
||||
.map(|e| e.into_envelope(&map))
|
||||
.collect())
|
||||
if account.minimal_sync() || remote {
|
||||
get_thread_messages_impl(account_id, account.use_proxy, &thread_id).await
|
||||
} else {
|
||||
let thread_id_num: u64 = thread_id.parse().map_err(|_| {
|
||||
raise_error!(
|
||||
format!(
|
||||
"Invalid thread_id: '{}'. thread_id must be a numeric string that can be parsed into a number.",
|
||||
thread_id
|
||||
),
|
||||
ErrorCode::InvalidParameter
|
||||
)
|
||||
})?;
|
||||
let envelopes = GmailEnvelope::get_thread(account_id, thread_id_num).await?;
|
||||
let map = GmailClient::for_get_label_name(account_id, account.use_proxy).await?;
|
||||
Ok(envelopes
|
||||
.into_iter()
|
||||
.map(|e| e.into_envelope(&map))
|
||||
.collect())
|
||||
}
|
||||
}
|
||||
MailerType::GraphApi => {
|
||||
let envelopes = OutlookEnvelope::get_thread(account_id, thread_id).await?;
|
||||
Ok(envelopes.into_iter().map(|e| e.into()).collect())
|
||||
if account.minimal_sync() || remote {
|
||||
let resp =
|
||||
OutlookClient::get_thread_messages(account_id, account.use_proxy, &thread_id)
|
||||
.await?;
|
||||
let envelopes: Vec<Envelope> = resp
|
||||
.value
|
||||
.into_iter()
|
||||
.map(|m| {
|
||||
let mut envelope: OutlookEnvelope = m.try_into()?;
|
||||
envelope.account_id = account.id;
|
||||
envelope.folder_id = 0;
|
||||
envelope.folder_name = "".to_string();
|
||||
let conversation_id = envelope.conversation_id.clone();
|
||||
let mut e = Envelope::from(envelope);
|
||||
e.thread_id = conversation_id.unwrap_or("unknown".into());
|
||||
Ok(e)
|
||||
})
|
||||
.collect::<RustMailerResult<Vec<Envelope>>>()?;
|
||||
Ok(envelopes)
|
||||
} else {
|
||||
let thread_id_num: u64 = thread_id.parse().map_err(|_| {
|
||||
raise_error!(
|
||||
format!(
|
||||
"Invalid thread_id: '{}'. thread_id must be a numeric string that can be parsed into a number.",
|
||||
thread_id
|
||||
),
|
||||
ErrorCode::InvalidParameter
|
||||
)
|
||||
})?;
|
||||
let envelopes = OutlookEnvelope::get_thread(account_id, thread_id_num).await?;
|
||||
Ok(envelopes.into_iter().map(Into::into).collect())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -522,7 +522,7 @@ impl MessageSearchRequest {
|
||||
|
||||
let query = self.search.to_gmail_api_search_command()?;
|
||||
let label_map: AHashMap<String, String> =
|
||||
GmailClient::reverse_label_map(account.id, account.use_proxy, false).await?;
|
||||
GmailClient::for_lookup_label_id(account.id, account.use_proxy, false).await?;
|
||||
|
||||
let label_id = match self.mailbox.as_deref() {
|
||||
Some(name) => label_map.get(name).cloned().map(Some).ok_or_else(|| {
|
||||
@@ -573,6 +573,8 @@ impl MessageSearchRequest {
|
||||
})
|
||||
.await?;
|
||||
|
||||
let label_map = GmailClient::for_get_label_name(account.id, account.use_proxy).await?;
|
||||
|
||||
let envelopes: Vec<Envelope> = batch_messages
|
||||
.into_iter()
|
||||
.map(|m| {
|
||||
@@ -821,7 +823,7 @@ impl UnifiedSearchRequest {
|
||||
})?
|
||||
.into(),
|
||||
MailerType::GmailApi => {
|
||||
let label_map = GmailClient::label_map(account_id, account.use_proxy).await?;
|
||||
let label_map = GmailClient::for_get_label_name(account_id, account.use_proxy).await?;
|
||||
let envelope = GmailEnvelope::get(id).await?.ok_or_else(|| {
|
||||
raise_error!(
|
||||
format!(
|
||||
|
||||
@@ -172,7 +172,7 @@ pub async fn tag_messages_impl(account_id: u64, payload: BatchTagRequest) -> Rus
|
||||
}
|
||||
MailerType::GmailApi => {
|
||||
let labels_map =
|
||||
GmailClient::reverse_label_map(account_id, account.use_proxy, true).await?;
|
||||
GmailClient::for_lookup_label_id(account_id, account.use_proxy, true).await?;
|
||||
let tags_to_process = &payload.tags;
|
||||
let mut target_label_ids: Vec<String> = Vec::with_capacity(tags_to_process.len());
|
||||
for tag_name in tags_to_process {
|
||||
|
||||
@@ -137,7 +137,7 @@ pub async fn transfer_messages(
|
||||
}
|
||||
|
||||
let labels_map =
|
||||
GmailClient::reverse_label_map(account_id, account.use_proxy, true).await?;
|
||||
GmailClient::for_lookup_label_id(account_id, account.use_proxy, true).await?;
|
||||
match transfer {
|
||||
MessageTransfer::Move => {
|
||||
let target_label_id =
|
||||
|
||||
Reference in New Issue
Block a user