File: Email\Email.shared.cs
Web Access
Project: src\src\Essentials\src\Essentials.csproj (Microsoft.Maui.Essentials)
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Maui.Storage;
 
namespace Microsoft.Maui.ApplicationModel.Communication
{
	/// <summary>
	/// Provides an easy way to allow the user to send emails.
	/// </summary>
	public interface IEmail
	{
		/// <summary>
		/// Gets a value indicating whether composing an email is supported on this device.
		/// </summary>
		bool IsComposeSupported { get; }
 
		/// <summary>
		/// Opens the default email client to allow the user to send the message.
		/// </summary>
		/// <param name="message">Instance of <see cref="EmailMessage"/> containing details of the email message to compose.</param>
		/// <returns>A <see cref="Task"/> object with the current status of the asynchronous operation.</returns>
		Task ComposeAsync(EmailMessage? message);
	}
 
	/// <summary>
	/// Static class with extension methods for the <see cref="IEmail"/> APIs.
	/// </summary>
	public static class EmailExtensions
	{
		/// <summary>
		/// Opens the default email client to allow the user to send the message.
		/// </summary>
		/// <param name="email">The object this method is invoked on.</param>
		/// <returns>A <see cref="Task"/> object with the current status of the asynchronous operation.</returns>
		public static Task ComposeAsync(this IEmail email) =>
			email.ComposeAsync(null);
 
		/// <summary>
		/// Opens the default email client to allow the user to send the message with the provided subject, body, and recipients.
		/// </summary>
		/// <param name="email">The object this method is invoked on.</param>
		/// <param name="subject">The email subject.</param>
		/// <param name="body">The email body.</param>
		/// <param name="to">The email recipients.</param>
		/// <returns>A <see cref="Task"/> object with the current status of the asynchronous operation.</returns>
		public static Task ComposeAsync(this IEmail email, string subject, string body, params string[] to) =>
			email.ComposeAsync(new EmailMessage(subject, body, to));
	}
 
	partial class EmailImplementation : IEmail
	{
		public Task ComposeAsync(EmailMessage? message)
		{
			if (!IsComposeSupported)
				throw new FeatureNotSupportedException();
 
			return PlatformComposeAsync(message);
		}
 
		internal static string GetMailToUri(EmailMessage message) =>
			"mailto:?" + string.Join("&", Parameters(message));
 
		static IEnumerable<string> Parameters(EmailMessage message)
		{
			if (message.To?.Count > 0)
				yield return "to=" + Recipients(message.To);
 
			if (message.Cc?.Count > 0)
				yield return "cc=" + Recipients(message.Cc);
 
			if (message.Bcc?.Count > 0)
				yield return "bcc=" + Recipients(message.Bcc);
 
			if (!string.IsNullOrWhiteSpace(message.Subject))
				yield return "subject=" + Uri.EscapeDataString(message.Subject);
 
			if (!string.IsNullOrWhiteSpace(message.Body))
				yield return "body=" + Uri.EscapeDataString(message.Body);
		}
 
		static string Recipients(IEnumerable<string> addresses) =>
			string.Join(",", addresses.Select(Uri.EscapeDataString));
	}
 
	/// <summary>
	/// Provides an easy way to allow the user to send emails.
	/// </summary>
	public static class Email
	{
		/// <summary>
		/// Opens the default email client to allow the user to send the message.
		/// </summary>
		/// <returns>A <see cref="Task"/> object with the current status of the asynchronous operation.</returns>
		public static Task ComposeAsync() =>
			Default.ComposeAsync();
 
		/// <summary>
		/// Opens the default email client to allow the user to send the message with the provided subject, body, and recipients.
		/// </summary>
		/// <param name="subject">The email subject.</param>
		/// <param name="body">The email body.</param>
		/// <param name="to">The email recipients.</param>
		/// <returns>A <see cref="Task"/> object with the current status of the asynchronous operation.</returns>
		public static Task ComposeAsync(string subject, string body, params string[] to) =>
			Default.ComposeAsync(subject, body, to);
 
		/// <summary>
		/// Opens the default email client to allow the user to send the message.
		/// </summary>
		/// <param name="message">Instance of <see cref="EmailMessage"/> containing details of the email message to compose.</param>
		/// <returns>A <see cref="Task"/> object with the current status of the asynchronous operation.</returns>
		public static Task ComposeAsync(EmailMessage message) =>
			Default.ComposeAsync(message);
 
		static IEmail? defaultImplementation;
 
		/// <summary>
		/// Provides the default implementation for static usage of this API.
		/// </summary>
		public static IEmail Default =>
			defaultImplementation ??= new EmailImplementation();
 
		internal static void SetDefault(IEmail? implementation) =>
			defaultImplementation = implementation;
	}
 
	/// <summary>
	/// Represents a single email message.
	/// </summary>
	public class EmailMessage
	{
		/// <summary>
		/// Initializes a new instance of the <see cref="EmailMessage"/> class.
		/// </summary>
		public EmailMessage()
		{
		}
 
		/// <summary>
		/// Initializes a new instance of the <see cref="EmailMessage"/> class with the specified subject, body, and recipients.
		/// </summary>
		/// <param name="subject">The email subject.</param>
		/// <param name="body">The email body.</param>
		/// <param name="to">The email recipients.</param>
		public EmailMessage(string subject, string body, params string[] to)
		{
			Subject = subject;
			Body = body;
			To = to?.ToList() ?? new List<string>();
		}
 
		/// <summary>
		/// Gets or sets the email's subject.
		/// </summary>
		public string? Subject { get; set; }
 
		/// <summary>
		/// Gets or sets the email's body.
		/// </summary>
		public string? Body { get; set; }
 
		/// <summary>
		/// Gets or sets a value indicating whether the message is in plain text or HTML.
		/// </summary>
		/// <remarks><see cref="EmailBodyFormat.Html"/> is not supported on Windows.</remarks>
		public EmailBodyFormat BodyFormat { get; set; }
 
		/// <summary>
		/// Gets or sets the email's recipients.
		/// </summary>
		public List<string>? To { get; set; } = new List<string>();
 
		/// <summary>
		/// Gets or sets the email's CC (Carbon Copy) recipients.
		/// </summary>
		public List<string>? Cc { get; set; } = new List<string>();
 
		/// <summary>
		/// Gets or sets the email's BCC (Blind Carbon Copy) recipients.
		/// </summary>
		public List<string>? Bcc { get; set; } = new List<string>();
 
		/// <summary>
		/// Gets or sets a list of file attachments as <see cref="EmailAttachment"/> objects.
		/// </summary>
		public List<EmailAttachment>? Attachments { get; set; } = new List<EmailAttachment>();
	}
 
	/// <summary>
	/// Represents various types of email body formats.
	/// </summary>
	public enum EmailBodyFormat
	{
		/// <summary>The email message body is plain text.</summary>
		PlainText,
 
		/// <summary>The email message body is HTML (not supported on Windows).</summary>
		Html
	}
 
	/// <summary>
	/// Represents a email file attachment.
	/// </summary>
	public partial class EmailAttachment : FileBase
	{
		/// <summary>
		/// Initializes a new instance of the <see cref="EmailAttachment"/> class based off the file specified in the provided path.
		/// </summary>
		/// <param name="fullPath">Full path and filename to file on filesystem.</param>
		public EmailAttachment(string fullPath)
			: base(fullPath)
		{
		}
 
		/// <summary>
		/// Initializes a new instance of the <see cref="EmailAttachment"/> class based off the file specified in the provided path
		/// and providing an explicit MIME filetype.
		/// </summary>
		/// <param name="fullPath">Full path and filename to file on filesystem.</param>
		/// <param name="contentType">Content type (MIME type) of the file (e.g.: <c>image/png</c>).</param>
		public EmailAttachment(string fullPath, string contentType)
			: base(fullPath, contentType)
		{
		}
 
		/// <summary>
		/// Initializes a new instance of the <see cref="EmailAttachment"/> class based off a <see cref="FileBase"/> object.
		/// </summary>
		/// <param name="file">An instance of <see cref="FileBase"/> with file information.</param>
		public EmailAttachment(FileBase file)
			: base(file)
		{
		}
	}
}