Skip to main content

io_msgraph/v1/
client.rs

1//! Std-blocking Microsoft Graph client: wraps a `Read + Write` stream
2//! plus the bearer credential and runs the coroutines against
3//! `graph.microsoft.com`. Gated behind the `client` feature.
4
5#[cfg(any(
6    feature = "rustls-aws",
7    feature = "rustls-ring",
8    feature = "native-tls"
9))]
10use core::time::Duration;
11use core::{any::Any, fmt};
12
13use alloc::{
14    boxed::Box,
15    string::{String, ToString},
16    vec::Vec,
17};
18use std::io::{self, Read, Write};
19
20use io_http::rfc6750::bearer::HttpAuthBearer;
21#[cfg(any(
22    feature = "rustls-aws",
23    feature = "rustls-ring",
24    feature = "native-tls"
25))]
26use pimalaya_stream::std::stream::StreamStd;
27/// TLS backend selection re-exported from pimalaya-stream, feeding
28/// [`MsgraphClientStdConnectOptions::tls`].
29#[cfg(any(
30    feature = "rustls-aws",
31    feature = "rustls-ring",
32    feature = "native-tls"
33))]
34pub use pimalaya_stream::tls::*;
35use thiserror::Error;
36#[cfg(any(
37    feature = "rustls-aws",
38    feature = "rustls-ring",
39    feature = "native-tls"
40))]
41use url::Url;
42
43#[cfg(any(
44    feature = "rustls-aws",
45    feature = "rustls-ring",
46    feature = "native-tls"
47))]
48use crate::v1::send::MSGRAPH_API_BASE;
49use crate::{
50    coroutine::*,
51    v1::rest::users::{
52        MsgraphUser,
53        contact_folders::{
54            MsgraphContactFolder, MsgraphContactFoldersListResponse,
55            child_folders::MsgraphContactChildFoldersList, create::MsgraphContactFolderCreate,
56            delete::MsgraphContactFolderDelete, get::MsgraphContactFolderGet,
57            list::MsgraphContactFoldersList, list::MsgraphContactFoldersListParams,
58            update::MsgraphContactFolderUpdate,
59        },
60        contacts::{
61            MsgraphContact, MsgraphContactsDeltaResponse, MsgraphContactsListResponse,
62            create::MsgraphContactCreate, delete::MsgraphContactDelete,
63            delta::MsgraphContactsDelta, get::MsgraphContactGet, list::MsgraphContactsList,
64            list::MsgraphContactsListParams, update::MsgraphContactUpdate,
65        },
66        get::MsgraphUserGet,
67        mail_folders::{
68            MsgraphMailFolder, MsgraphMailFoldersListResponse,
69            child_folders::MsgraphMailChildFoldersList, copy::MsgraphMailFolderCopy,
70            create::MsgraphMailFolderCreate, delete::MsgraphMailFolderDelete,
71            get::MsgraphMailFolderGet, list::MsgraphMailFoldersList,
72            list::MsgraphMailFoldersListParams, r#move::MsgraphMailFolderMove,
73            update::MsgraphMailFolderUpdate,
74        },
75        messages::{
76            MsgraphMessage, MsgraphMessagesListResponse,
77            attachments::{
78                MsgraphAttachment, MsgraphAttachmentsListResponse, create::MsgraphAttachmentCreate,
79                delete::MsgraphAttachmentDelete, get_raw::MsgraphAttachmentGetRaw,
80                list::MsgraphAttachmentsList,
81            },
82            copy::MsgraphMessageCopy,
83            create::MsgraphMessageCreate,
84            create_mime::MsgraphMessageCreateMime,
85            delete::MsgraphMessageDelete,
86            get::MsgraphMessageGet,
87            get_raw::MsgraphMessageGetRaw,
88            list::MsgraphMessagesList,
89            list::MsgraphMessagesListParams,
90            r#move::MsgraphMessageMove,
91            send::MsgraphMessageSend,
92            update::MsgraphMessageUpdate,
93        },
94        send_mail::{MsgraphMailSend, MsgraphMailSendMime},
95    },
96    v1::send::{MsgraphNoResponse, MsgraphSendError, MsgraphSendOutput},
97};
98
99/// Error returned by [`MsgraphClientStd`] operations.
100#[derive(Debug, Error)]
101pub enum MsgraphClientStdError {
102    /// A coroutine completed with an error.
103    #[error(transparent)]
104    Send(#[from] MsgraphSendError),
105    /// Reading from or writing to the stream failed.
106    #[error(transparent)]
107    Io(#[from] io::Error),
108    /// Opening the TCP/TLS connection failed.
109    #[cfg(any(
110        feature = "rustls-aws",
111        feature = "rustls-ring",
112        feature = "native-tls"
113    ))]
114    #[error(transparent)]
115    Tls(#[from] anyhow::Error),
116    /// The API base URL has no host to connect to.
117    #[cfg(any(
118        feature = "rustls-aws",
119        feature = "rustls-ring",
120        feature = "native-tls"
121    ))]
122    #[error("Microsoft Graph URL `{0}` has no host")]
123    UrlMissingHost(String),
124    /// The API base URL scheme is neither http nor https.
125    #[cfg(any(
126        feature = "rustls-aws",
127        feature = "rustls-ring",
128        feature = "native-tls"
129    ))]
130    #[error(
131        "Microsoft Graph URL `{url}` has unsupported scheme `{scheme}` (expected `http` or `https`)"
132    )]
133    UrlUnsupportedScheme {
134        /// The rejected API base URL.
135        url: String,
136        /// The scheme of the rejected URL.
137        scheme: String,
138    },
139}
140
141/// Optional settings for [`MsgraphClientStd::connect`]; every field has a
142/// default (the TLS backend default, and `me` as the mailbox owner).
143pub struct MsgraphClientStdConnectOptions {
144    /// The TLS backend configuration used to open the connection.
145    #[cfg(any(
146        feature = "rustls-aws",
147        feature = "rustls-ring",
148        feature = "native-tls"
149    ))]
150    pub tls: Tls,
151    /// The mailbox owner: `me`, a user id or a principal name.
152    pub user_id: String,
153}
154
155impl Default for MsgraphClientStdConnectOptions {
156    fn default() -> Self {
157        Self {
158            #[cfg(any(
159                feature = "rustls-aws",
160                feature = "rustls-ring",
161                feature = "native-tls"
162            ))]
163            tls: Tls::default(),
164            user_id: String::from("me"),
165        }
166    }
167}
168
169const READ_BUFFER_SIZE: usize = 16 * 1024;
170
171/// Std blocking Microsoft Graph client: a stream, the bearer
172/// credential and the mailbox owner, with one method per operation.
173pub struct MsgraphClientStd {
174    /// The stream carrying the HTTPS connection to the Graph API.
175    pub stream: Box<dyn MsgraphStream>,
176    /// The bearer credential added to every request.
177    pub auth: HttpAuthBearer,
178    /// The mailbox owner: `me`, a user id or a principal name.
179    pub user_id: String,
180}
181
182impl MsgraphClientStd {
183    /// Builds a client over a caller-managed stream.
184    pub fn new<S: Read + Write + Send + 'static>(
185        stream: S,
186        token: impl ToString,
187        options: MsgraphClientStdConnectOptions,
188    ) -> Self {
189        Self {
190            stream: Box::new(stream),
191            auth: HttpAuthBearer::new(token.to_string()),
192            user_id: options.user_id,
193        }
194    }
195
196    /// Builds a client by opening a TCP/TLS connection to the Graph
197    /// API endpoint through pimalaya-stream.
198    #[cfg(any(
199        feature = "rustls-aws",
200        feature = "rustls-ring",
201        feature = "native-tls"
202    ))]
203    pub fn connect(
204        token: impl ToString,
205        options: MsgraphClientStdConnectOptions,
206    ) -> Result<Self, MsgraphClientStdError> {
207        let MsgraphClientStdConnectOptions { tls, user_id } = options;
208
209        let url = Url::parse(MSGRAPH_API_BASE).expect("Microsoft Graph API base URL is valid");
210        let host = url
211            .host_str()
212            .ok_or_else(|| MsgraphClientStdError::UrlMissingHost(url.to_string()))?;
213
214        let stream = match url.scheme() {
215            "http" => StreamStd::connect_tcp(host, url.port().unwrap_or(80))?,
216            "https" => StreamStd::connect_tls(host, url.port().unwrap_or(443), &tls)?,
217            scheme => {
218                return Err(MsgraphClientStdError::UrlUnsupportedScheme {
219                    url: url.to_string(),
220                    scheme: scheme.to_string(),
221                });
222            }
223        };
224
225        stream.set_read_timeout(Some(Duration::from_secs(30)))?;
226
227        Ok(Self {
228            stream: Box::new(stream),
229            auth: HttpAuthBearer::new(token.to_string()),
230            user_id,
231        })
232    }
233
234    /// Replaces the underlying stream (e.g. after a connection reset).
235    pub fn set_stream<S: Read + Write + Send + 'static>(&mut self, stream: S) {
236        self.stream = Box::new(stream);
237    }
238
239    /// Runs the given coroutine to completion against the stream,
240    /// fulfilling its read and write requests.
241    pub fn run<C, T>(
242        &mut self,
243        mut coroutine: C,
244    ) -> Result<MsgraphSendOutput<T>, MsgraphClientStdError>
245    where
246        C: MsgraphCoroutine<
247                Yield = MsgraphYield,
248                Return = Result<MsgraphSendOutput<T>, MsgraphSendError>,
249            >,
250    {
251        let mut buf = [0u8; READ_BUFFER_SIZE];
252        let mut arg: Option<&[u8]> = None;
253
254        loop {
255            match coroutine.resume(arg.take()) {
256                MsgraphCoroutineState::Complete(Ok(out)) => return Ok(out),
257                MsgraphCoroutineState::Complete(Err(err)) => return Err(err.into()),
258                MsgraphCoroutineState::Yielded(MsgraphYield::WantsRead) => {
259                    let n = self.stream.read(&mut buf)?;
260                    arg = Some(&buf[..n]);
261                }
262                MsgraphCoroutineState::Yielded(MsgraphYield::WantsWrite(bytes)) => {
263                    self.stream.write_all(&bytes)?;
264                    arg = None;
265                }
266            }
267        }
268    }
269
270    /// Gets the profile of the mailbox owner.
271    pub fn me(&mut self) -> Result<MsgraphSendOutput<MsgraphUser>, MsgraphClientStdError> {
272        let coroutine = MsgraphUserGet::new(&self.auth, &self.user_id)?;
273        self.run(coroutine)
274    }
275
276    /// Lists the mail folders of the mailbox.
277    pub fn mail_folders_list(
278        &mut self,
279        params: &MsgraphMailFoldersListParams,
280    ) -> Result<MsgraphSendOutput<MsgraphMailFoldersListResponse>, MsgraphClientStdError> {
281        let coroutine = MsgraphMailFoldersList::new(&self.auth, &self.user_id, params)?;
282        self.run(coroutine)
283    }
284
285    /// Gets a mail folder by id.
286    pub fn mail_folder_get(
287        &mut self,
288        id: &str,
289    ) -> Result<MsgraphSendOutput<MsgraphMailFolder>, MsgraphClientStdError> {
290        let coroutine = MsgraphMailFolderGet::new(&self.auth, &self.user_id, id)?;
291        self.run(coroutine)
292    }
293
294    /// Creates a mail folder.
295    pub fn mail_folder_create(
296        &mut self,
297        folder: &MsgraphMailFolder,
298    ) -> Result<MsgraphSendOutput<MsgraphMailFolder>, MsgraphClientStdError> {
299        let coroutine = MsgraphMailFolderCreate::new(&self.auth, &self.user_id, folder)?;
300        self.run(coroutine)
301    }
302
303    /// Updates a mail folder by id.
304    pub fn mail_folder_update(
305        &mut self,
306        id: &str,
307        folder: &MsgraphMailFolder,
308    ) -> Result<MsgraphSendOutput<MsgraphMailFolder>, MsgraphClientStdError> {
309        let coroutine = MsgraphMailFolderUpdate::new(&self.auth, &self.user_id, id, folder)?;
310        self.run(coroutine)
311    }
312
313    /// Deletes a mail folder by id.
314    pub fn mail_folder_delete(
315        &mut self,
316        id: &str,
317    ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
318        let coroutine = MsgraphMailFolderDelete::new(&self.auth, &self.user_id, id)?;
319        self.run(coroutine)
320    }
321
322    /// Copies a mail folder into a destination folder.
323    pub fn mail_folder_copy(
324        &mut self,
325        id: &str,
326        destination: &str,
327    ) -> Result<MsgraphSendOutput<MsgraphMailFolder>, MsgraphClientStdError> {
328        let coroutine = MsgraphMailFolderCopy::new(&self.auth, &self.user_id, id, destination)?;
329        self.run(coroutine)
330    }
331
332    /// Moves a mail folder into a destination folder.
333    pub fn mail_folder_move(
334        &mut self,
335        id: &str,
336        destination: &str,
337    ) -> Result<MsgraphSendOutput<MsgraphMailFolder>, MsgraphClientStdError> {
338        let coroutine = MsgraphMailFolderMove::new(&self.auth, &self.user_id, id, destination)?;
339        self.run(coroutine)
340    }
341
342    /// Lists the child folders of a mail folder.
343    pub fn mail_child_folders_list(
344        &mut self,
345        id: &str,
346        params: &MsgraphMailFoldersListParams,
347    ) -> Result<MsgraphSendOutput<MsgraphMailFoldersListResponse>, MsgraphClientStdError> {
348        let coroutine = MsgraphMailChildFoldersList::new(&self.auth, &self.user_id, id, params)?;
349        self.run(coroutine)
350    }
351
352    /// Lists the contact folders of the mailbox.
353    pub fn contact_folders_list(
354        &mut self,
355        params: &MsgraphContactFoldersListParams,
356    ) -> Result<MsgraphSendOutput<MsgraphContactFoldersListResponse>, MsgraphClientStdError> {
357        let coroutine = MsgraphContactFoldersList::new(&self.auth, &self.user_id, params)?;
358        self.run(coroutine)
359    }
360
361    /// Gets a contact folder by id.
362    pub fn contact_folder_get(
363        &mut self,
364        id: &str,
365    ) -> Result<MsgraphSendOutput<MsgraphContactFolder>, MsgraphClientStdError> {
366        let coroutine = MsgraphContactFolderGet::new(&self.auth, &self.user_id, id)?;
367        self.run(coroutine)
368    }
369
370    /// Creates a contact folder.
371    pub fn contact_folder_create(
372        &mut self,
373        folder: &MsgraphContactFolder,
374    ) -> Result<MsgraphSendOutput<MsgraphContactFolder>, MsgraphClientStdError> {
375        let coroutine = MsgraphContactFolderCreate::new(&self.auth, &self.user_id, folder)?;
376        self.run(coroutine)
377    }
378
379    /// Updates a contact folder by id.
380    pub fn contact_folder_update(
381        &mut self,
382        id: &str,
383        folder: &MsgraphContactFolder,
384    ) -> Result<MsgraphSendOutput<MsgraphContactFolder>, MsgraphClientStdError> {
385        let coroutine = MsgraphContactFolderUpdate::new(&self.auth, &self.user_id, id, folder)?;
386        self.run(coroutine)
387    }
388
389    /// Deletes a contact folder by id.
390    pub fn contact_folder_delete(
391        &mut self,
392        id: &str,
393    ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
394        let coroutine = MsgraphContactFolderDelete::new(&self.auth, &self.user_id, id)?;
395        self.run(coroutine)
396    }
397
398    /// Lists the child folders of a contact folder.
399    pub fn contact_child_folders_list(
400        &mut self,
401        id: &str,
402        params: &MsgraphContactFoldersListParams,
403    ) -> Result<MsgraphSendOutput<MsgraphContactFoldersListResponse>, MsgraphClientStdError> {
404        let coroutine = MsgraphContactChildFoldersList::new(&self.auth, &self.user_id, id, params)?;
405        self.run(coroutine)
406    }
407
408    /// Lists the contacts of the default Contacts folder, or of the
409    /// given contact folder.
410    pub fn contacts_list(
411        &mut self,
412        folder: Option<&str>,
413        params: &MsgraphContactsListParams,
414    ) -> Result<MsgraphSendOutput<MsgraphContactsListResponse>, MsgraphClientStdError> {
415        let coroutine = MsgraphContactsList::new(&self.auth, &self.user_id, folder, params)?;
416        self.run(coroutine)
417    }
418
419    /// Gets a contact by id, optionally expanding the given relations.
420    pub fn contact_get(
421        &mut self,
422        id: &str,
423        expand: Option<&str>,
424    ) -> Result<MsgraphSendOutput<MsgraphContact>, MsgraphClientStdError> {
425        let coroutine = MsgraphContactGet::new(&self.auth, &self.user_id, id, expand)?;
426        self.run(coroutine)
427    }
428
429    /// Creates a contact in the default Contacts folder, or in the
430    /// given contact folder.
431    pub fn contact_create(
432        &mut self,
433        folder: Option<&str>,
434        contact: &MsgraphContact,
435    ) -> Result<MsgraphSendOutput<MsgraphContact>, MsgraphClientStdError> {
436        let coroutine = MsgraphContactCreate::new(&self.auth, &self.user_id, folder, contact)?;
437        self.run(coroutine)
438    }
439
440    /// Updates a contact by id.
441    pub fn contact_update(
442        &mut self,
443        id: &str,
444        contact: &MsgraphContact,
445    ) -> Result<MsgraphSendOutput<MsgraphContact>, MsgraphClientStdError> {
446        let coroutine = MsgraphContactUpdate::new(&self.auth, &self.user_id, id, contact)?;
447        self.run(coroutine)
448    }
449
450    /// Deletes a contact by id.
451    pub fn contact_delete(
452        &mut self,
453        id: &str,
454    ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
455        let coroutine = MsgraphContactDelete::new(&self.auth, &self.user_id, id)?;
456        self.run(coroutine)
457    }
458
459    /// Starts a contacts delta round over the default Contacts folder,
460    /// or over the given contact folder.
461    pub fn contacts_delta(
462        &mut self,
463        folder: Option<&str>,
464        select: Option<&str>,
465    ) -> Result<MsgraphSendOutput<MsgraphContactsDeltaResponse>, MsgraphClientStdError> {
466        let coroutine = MsgraphContactsDelta::new(&self.auth, &self.user_id, folder, select)?;
467        self.run(coroutine)
468    }
469
470    /// Lists the messages of the whole mailbox, or of the given mail
471    /// folder.
472    pub fn messages_list(
473        &mut self,
474        folder: Option<&str>,
475        params: &MsgraphMessagesListParams,
476    ) -> Result<MsgraphSendOutput<MsgraphMessagesListResponse>, MsgraphClientStdError> {
477        let coroutine = MsgraphMessagesList::new(&self.auth, &self.user_id, folder, params)?;
478        self.run(coroutine)
479    }
480
481    /// Gets a message by id.
482    pub fn message_get(
483        &mut self,
484        id: &str,
485    ) -> Result<MsgraphSendOutput<MsgraphMessage>, MsgraphClientStdError> {
486        let coroutine = MsgraphMessageGet::new(&self.auth, &self.user_id, id)?;
487        self.run(coroutine)
488    }
489
490    /// Gets the raw RFC 5322 MIME content of a message by id.
491    pub fn message_get_raw(
492        &mut self,
493        id: &str,
494    ) -> Result<MsgraphSendOutput<Vec<u8>>, MsgraphClientStdError> {
495        let coroutine = MsgraphMessageGetRaw::new(&self.auth, &self.user_id, id)?;
496        self.run(coroutine)
497    }
498
499    /// Creates a draft message from JSON in the Drafts folder, or in
500    /// the given mail folder.
501    pub fn message_create(
502        &mut self,
503        folder: Option<&str>,
504        message: &MsgraphMessage,
505    ) -> Result<MsgraphSendOutput<MsgraphMessage>, MsgraphClientStdError> {
506        let coroutine = MsgraphMessageCreate::new(&self.auth, &self.user_id, folder, message)?;
507        self.run(coroutine)
508    }
509
510    /// Creates a draft message from raw RFC 5322 MIME bytes in the
511    /// Drafts folder, or in the given mail folder.
512    pub fn message_create_mime(
513        &mut self,
514        folder: Option<&str>,
515        raw: &[u8],
516    ) -> Result<MsgraphSendOutput<MsgraphMessage>, MsgraphClientStdError> {
517        let coroutine = MsgraphMessageCreateMime::new(&self.auth, &self.user_id, folder, raw)?;
518        self.run(coroutine)
519    }
520
521    /// Updates a message by id.
522    pub fn message_update(
523        &mut self,
524        id: &str,
525        message: &MsgraphMessage,
526    ) -> Result<MsgraphSendOutput<MsgraphMessage>, MsgraphClientStdError> {
527        let coroutine = MsgraphMessageUpdate::new(&self.auth, &self.user_id, id, message)?;
528        self.run(coroutine)
529    }
530
531    /// Deletes a message by id.
532    pub fn message_delete(
533        &mut self,
534        id: &str,
535    ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
536        let coroutine = MsgraphMessageDelete::new(&self.auth, &self.user_id, id)?;
537        self.run(coroutine)
538    }
539
540    /// Moves a message into a destination folder.
541    pub fn message_move(
542        &mut self,
543        id: &str,
544        destination: &str,
545    ) -> Result<MsgraphSendOutput<MsgraphMessage>, MsgraphClientStdError> {
546        let coroutine = MsgraphMessageMove::new(&self.auth, &self.user_id, id, destination)?;
547        self.run(coroutine)
548    }
549
550    /// Copies a message into a destination folder.
551    pub fn message_copy(
552        &mut self,
553        id: &str,
554        destination: &str,
555    ) -> Result<MsgraphSendOutput<MsgraphMessage>, MsgraphClientStdError> {
556        let coroutine = MsgraphMessageCopy::new(&self.auth, &self.user_id, id, destination)?;
557        self.run(coroutine)
558    }
559
560    /// Creates a file attachment on a message.
561    pub fn attachment_create(
562        &mut self,
563        message_id: &str,
564        name: &str,
565        content: &[u8],
566        content_type: Option<&str>,
567    ) -> Result<MsgraphSendOutput<MsgraphAttachment>, MsgraphClientStdError> {
568        let coroutine = MsgraphAttachmentCreate::new(
569            &self.auth,
570            &self.user_id,
571            message_id,
572            name,
573            content,
574            content_type,
575        )?;
576        self.run(coroutine)
577    }
578
579    /// Lists the attachments of a message.
580    pub fn attachments_list(
581        &mut self,
582        message_id: &str,
583    ) -> Result<MsgraphSendOutput<MsgraphAttachmentsListResponse>, MsgraphClientStdError> {
584        let coroutine = MsgraphAttachmentsList::new(&self.auth, &self.user_id, message_id)?;
585        self.run(coroutine)
586    }
587
588    /// Gets the raw content of an attachment.
589    pub fn attachment_get_raw(
590        &mut self,
591        message_id: &str,
592        attachment_id: &str,
593    ) -> Result<MsgraphSendOutput<Vec<u8>>, MsgraphClientStdError> {
594        let coroutine =
595            MsgraphAttachmentGetRaw::new(&self.auth, &self.user_id, message_id, attachment_id)?;
596        self.run(coroutine)
597    }
598
599    /// Deletes an attachment of a message.
600    pub fn attachment_delete(
601        &mut self,
602        message_id: &str,
603        attachment_id: &str,
604    ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
605        let coroutine =
606            MsgraphAttachmentDelete::new(&self.auth, &self.user_id, message_id, attachment_id)?;
607        self.run(coroutine)
608    }
609
610    /// Sends an existing draft message by id.
611    pub fn message_send(
612        &mut self,
613        id: &str,
614    ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
615        let coroutine = MsgraphMessageSend::new(&self.auth, &self.user_id, id)?;
616        self.run(coroutine)
617    }
618
619    /// Sends a message described as JSON through the sendMail action.
620    pub fn mail_send(
621        &mut self,
622        message: &MsgraphMessage,
623        save_to_sent_items: bool,
624    ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
625        let coroutine =
626            MsgraphMailSend::new(&self.auth, &self.user_id, message, save_to_sent_items)?;
627        self.run(coroutine)
628    }
629
630    /// Sends a message given as raw RFC 5322 MIME bytes through the
631    /// sendMail action.
632    pub fn mail_send_mime(
633        &mut self,
634        raw: &[u8],
635    ) -> Result<MsgraphSendOutput<MsgraphNoResponse>, MsgraphClientStdError> {
636        let coroutine = MsgraphMailSendMime::new(&self.auth, &self.user_id, raw)?;
637        self.run(coroutine)
638    }
639}
640
641impl fmt::Debug for MsgraphClientStd {
642    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
643        f.debug_struct("MsgraphClientStd")
644            .field("auth", &self.auth)
645            .field("user_id", &self.user_id)
646            .finish_non_exhaustive()
647    }
648}
649
650/// Blocking stream the client runs over, downcastable through `Any`
651/// (e.g. to recover a concrete TLS stream).
652pub trait MsgraphStream: Read + Write + Send + Any {
653    /// The stream as a mutable `Any`, ready for downcasting.
654    fn as_any_mut(&mut self) -> &mut dyn Any;
655}
656
657impl<T: Read + Write + Send + Any> MsgraphStream for T {
658    fn as_any_mut(&mut self) -> &mut dyn Any {
659        self
660    }
661}