mirror of
https://github.com/rustmailer/rustmailer.git
synced 2026-09-12 00:04:58 +00:00
feat(grpc): add tag_messages support for message tagging via gRPC
This commit is contained in:
@@ -1162,6 +1162,49 @@ message AppendReplyToDraftRequest {
|
||||
optional bool reply_all = 8;
|
||||
}
|
||||
|
||||
// Represents a tag (Label/Category/Flag) and its associated color
|
||||
message TagAndColor {
|
||||
// Name of the label, category, or IMAP custom flag
|
||||
string name = 1;
|
||||
|
||||
// Predefined Outlook category presets (e.g., "preset0", "preset1")
|
||||
// Only used for Microsoft Graph API
|
||||
optional string graph_color = 2;
|
||||
|
||||
// Custom hex colors for Gmail API
|
||||
optional LabelColor gmail_color = 3;
|
||||
}
|
||||
|
||||
// Defines the type of operation to be performed
|
||||
enum TagAction {
|
||||
// Adds tags to the specified messages
|
||||
ADD = 0;
|
||||
// Removes tags from the specified messages
|
||||
REMOVE = 1;
|
||||
// Overwrites the entire list of tags
|
||||
SET = 2;
|
||||
}
|
||||
|
||||
// The main request for batch tagging operations
|
||||
message BatchTagRequest {
|
||||
// The ID of the email account
|
||||
uint64 account_id = 1;
|
||||
// A list of unique message identifiers
|
||||
repeated string message_ids = 2;
|
||||
|
||||
// The list of tags/categories with their optional color info
|
||||
repeated TagAndColor tags = 3;
|
||||
|
||||
// The action to perform (Add, Remove, or Set)
|
||||
TagAction action = 4;
|
||||
|
||||
// Required for IMAP context (e.g., "INBOX")
|
||||
optional string mailbox_name = 5;
|
||||
|
||||
// Whether to create tags if they don't exist (Gmail/Graph only)
|
||||
optional bool auto_create_tags = 6;
|
||||
}
|
||||
|
||||
// MessageService provides APIs for interacting with email messages.
|
||||
service MessageService {
|
||||
// Moves messages from one mailbox to another.
|
||||
@@ -1190,6 +1233,14 @@ service MessageService {
|
||||
rpc UnifiedSearch(UnifiedSearchRequest) returns (PagedMessages);
|
||||
// Creates a reply draft email linked to an existing message thread.
|
||||
rpc AppendReplyToDraft(AppendReplyToDraftRequest) returns (Empty);
|
||||
// Batch modifies the custom tags, categories, or keywords on messages.
|
||||
// This interface is dedicated to operating on **user-defined labels** and is separate
|
||||
// from standard system status flags (like Read/Unread).
|
||||
// It unifies tagging across different email services:
|
||||
// - **Gmail/Graph API:** Operates on user-defined Label IDs or Category Names.
|
||||
// - **IMAP/SMTP:** Operates on custom IMAP Keywords (Custom Flags).
|
||||
// **Note:** This is a high-level operation designed for user tag management.
|
||||
rpc TagMessages(BatchTagRequest) returns (Empty);
|
||||
}
|
||||
|
||||
// Mta represents a Mail Transfer Agent configuration.
|
||||
|
||||
@@ -23,6 +23,7 @@ use crate::modules::{
|
||||
Condition, Conditions, Logic, MessageSearch, MessageSearchRequest, Operator,
|
||||
UnifiedSearchRequest,
|
||||
},
|
||||
tags::{BatchTagRequest, TagAction, TagAndColor},
|
||||
transfer::MailboxTransferRequest,
|
||||
},
|
||||
rest::response::{CursorDataPage, DataPage},
|
||||
@@ -618,3 +619,39 @@ impl From<rustmailer_grpc::AppendReplyToDraftRequest> for AppendReplyToDraftRequ
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<rustmailer_grpc::BatchTagRequest> for BatchTagRequest {
|
||||
type Error = &'static str;
|
||||
fn try_from(value: rustmailer_grpc::BatchTagRequest) -> Result<Self, Self::Error> {
|
||||
Ok(Self {
|
||||
message_ids: value.message_ids,
|
||||
tags: value.tags.into_iter().map(|t| t.into()).collect(),
|
||||
action: value.action.try_into()?,
|
||||
mailbox_name: value.mailbox_name,
|
||||
auto_create_tags: value.auto_create_tags,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<rustmailer_grpc::TagAndColor> for TagAndColor {
|
||||
fn from(value: rustmailer_grpc::TagAndColor) -> Self {
|
||||
Self {
|
||||
name: value.name,
|
||||
graph_color: value.graph_color,
|
||||
gmail_color: value.gmail_color.map(|c| c.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<i32> for TagAction {
|
||||
type Error = &'static str;
|
||||
|
||||
fn try_from(value: i32) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
0 => Ok(TagAction::Add),
|
||||
1 => Ok(TagAction::Remove),
|
||||
2 => Ok(TagAction::Set),
|
||||
_ => Err("Invalid value for TagAction"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ use crate::modules::common::auth::ClientContext;
|
||||
use crate::modules::error::code::ErrorCode;
|
||||
use crate::modules::grpc::auth::require_account_access;
|
||||
use crate::modules::grpc::service::rustmailer_grpc::{
|
||||
AppendReplyToDraftRequest, ByteResponse, CursorDataPage, EmailEnvelopeList,
|
||||
AppendReplyToDraftRequest, BatchTagRequest, ByteResponse, CursorDataPage, EmailEnvelopeList,
|
||||
GetThreadMessagesRequest, ListThreadsRequest, MessageContentResponse, PagedMessages,
|
||||
UnifiedSearchRequest,
|
||||
};
|
||||
@@ -29,6 +29,9 @@ use crate::modules::message::list::{
|
||||
};
|
||||
use crate::modules::message::search::payload::MessageSearchRequest as RustMailerMessageSearchRequest;
|
||||
use crate::modules::message::search::payload::UnifiedSearchRequest as RustMailerUnifiedSearchRequest;
|
||||
use crate::modules::message::tags::{
|
||||
tag_messages_impl, BatchTagRequest as RustMailerBatchTagRequest,
|
||||
};
|
||||
use crate::modules::message::transfer::{transfer_messages, MessageTransfer};
|
||||
use crate::raise_error;
|
||||
use poem_grpc::{Request, Response, Status};
|
||||
@@ -257,4 +260,17 @@ impl MessageService for RustMailerMessageService {
|
||||
request.append_reply_to_draft(account_id).await?;
|
||||
Ok(Response::new(Empty::default()))
|
||||
}
|
||||
|
||||
async fn tag_messages(
|
||||
&self,
|
||||
request: Request<BatchTagRequest>,
|
||||
) -> Result<Response<Empty>, Status> {
|
||||
let req = require_account_access(request, |r| r.account_id)?;
|
||||
let account_id = req.account_id;
|
||||
let request: RustMailerBatchTagRequest = req
|
||||
.try_into()
|
||||
.map_err(|e: &'static str| raise_error!(e.to_string(), ErrorCode::InvalidParameter))?;
|
||||
tag_messages_impl(account_id, request).await?;
|
||||
Ok(Response::new(Empty::default()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,9 +11,10 @@ use crate::{
|
||||
common::rustls::RustMailerTls,
|
||||
context::Initialize,
|
||||
grpc::service::rustmailer_grpc::{
|
||||
AppendReplyToDraftRequest, ExternalOAuth2Request, GetThreadMessagesRequest,
|
||||
ListMessagesRequest, ListThreadsRequest, MessageServiceClient, OAuth2ServiceClient,
|
||||
TemplateSentTestRequest, TemplatesServiceClient, UnifiedSearchRequest,
|
||||
AppendReplyToDraftRequest, BatchTagRequest, ExternalOAuth2Request,
|
||||
GetThreadMessagesRequest, ListMessagesRequest, ListThreadsRequest,
|
||||
MessageServiceClient, OAuth2ServiceClient, TagAndColor, TemplateSentTestRequest,
|
||||
TemplatesServiceClient, UnifiedSearchRequest,
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -84,7 +85,6 @@ async fn test2() {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
||||
async fn test3() {
|
||||
RustMailerTls::initialize().await.unwrap();
|
||||
|
||||
@@ -264,3 +264,35 @@ async fn test8() {
|
||||
);
|
||||
grpc_client.append_reply_to_draft(request).await.unwrap();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test9() {
|
||||
RustMailerTls::initialize().await.unwrap();
|
||||
let cfg = ClientConfig::builder()
|
||||
.uri("http://localhost:16630")
|
||||
.build()
|
||||
.unwrap();
|
||||
let mut grpc_client = MessageServiceClient::new(cfg);
|
||||
grpc_client.set_accept_compressed([CompressionEncoding::GZIP]);
|
||||
grpc_client.set_send_compressed(CompressionEncoding::GZIP);
|
||||
|
||||
let request = BatchTagRequest {
|
||||
account_id: 3815676991897752,
|
||||
message_ids: vec!["AQMkADAwATMwMAItNzE0OC1jZTEzLTAwAi0wMAoARgAAA_KUk7xWPSBEntPHShr61lgHAOo9V4GwHndCjf0x1uoIcwUAAAIBDAAAAOo9V4GwHndCjf0x1uoIcwUAAckOKwUAAAA=".into()],
|
||||
tags: vec![TagAndColor {
|
||||
name: "test_name2".into(),
|
||||
graph_color: Some("preset1".into()),
|
||||
gmail_color: None
|
||||
}],
|
||||
action: 2,
|
||||
mailbox_name: Some("INBOX".into()),
|
||||
auto_create_tags: Some(true),
|
||||
};
|
||||
|
||||
let mut request = poem_grpc::Request::new(request);
|
||||
request.metadata_mut().insert(
|
||||
AUTHORIZATION,
|
||||
format!("Bearer {}", "0ZRTSl2WhTOUQYMCgSm45i1o"),
|
||||
);
|
||||
grpc_client.tag_messages(request).await.unwrap();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user