/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use std::sync::Arc; use base64::prelude::*; use ms_graph_tb::{OperationBody, paths}; use protocol_shared::{ authentication::credentials::AuthenticationProvider, client::DoOperation, outgoing::{OwnedMailbox, SendCapableClient}, safe_xpcom::{SafeListener, SafeMsgOutgoingListener, SafeUri}, }; use xpcom::RefCounted; use crate::{client::XpComGraphClient, error::XpComGraphError}; struct DoSendMessage<'a> { pub endpoint: &'a url::Url, pub listener: &'a SafeMsgOutgoingListener, pub mime_content: String, pub _should_request_dsn: bool, pub _bcc_recipients: Vec, pub server_uri: SafeUri, } impl DoOperation, XpComGraphError> for DoSendMessage<'_> { const NAME: &'static str = "send message"; type Okay = (); type Listener = SafeMsgOutgoingListener; async fn do_operation( &mut self, client: &XpComGraphClient, ) -> Result { // Notify that the request has started. self.listener.on_send_start()?; // First, let's create a draft for the message by sending the server its // full RFC822 payload. We *could* send in one go with `/me/sendMail`, // but since that endpoint only takes *either* structured JSON or // base64-encoded RFC822 text, we wouldn't be able to append further // information like the DSN flag or the Bcc recipients. let endpoint = self.endpoint.as_str(); let body = BASE64_STANDARD.encode(&self.mime_content); let body = OperationBody::Other { content_type: "text/plain".to_string(), body: body.as_bytes().to_vec(), }; // Send the request and grab the resulting message ID. let request = paths::me_messages::Post::new(endpoint.to_string(), body); let message_id = client .send_request(request) .await? .outlook_item() .entity() .id()? .to_string(); // Now tell the server to send the draft message we just created. let request = paths::me_messages_message_id_send::Post::new(endpoint.to_string(), message_id); client.send_request(request).await?; Ok(()) } fn into_success_arg(self, _: Self::Okay) -> SafeUri { self.server_uri } fn into_failure_arg(self) -> ::OnFailureArg { (self.server_uri, None::).into() } } impl SendCapableClient for XpComGraphClient { /// Send a message via Graph. /// /// This first performs a [message creation] request, then a [message send] /// request. /// /// All headers except for Bcc are expected to be included in the provided /// MIME content. /// /// [message creation]: /// https://learn.microsoft.com/en-us/graph/api/user-post-messages /// [message send]: https://learn.microsoft.com/en-us/graph/api/message-send async fn send_message( self: Arc>, mime_content: String, _message_id: String, should_request_dsn: bool, bcc_recipients: Vec, listener: SafeMsgOutgoingListener, server_uri: SafeUri, ) { let operation = DoSendMessage { endpoint: &self.endpoint, listener: &listener, mime_content, _should_request_dsn: should_request_dsn, _bcc_recipients: bcc_recipients, server_uri, }; operation.handle_operation(&self, &listener).await; } }