C# Start a new MailTo Process and HTML URL Encoding

此生再无相见时 提交于 2019-12-06 16:13:47

问题


I have created a new MailTo extension method for the Process class which just fills the Process with a new ProcessStartinfo which contains the required mailto arguments. I have created a method called FormatMailToArgument (Right at the end) which converts control characters to their Url Encoded equivelants and have tested this and it works but is there a better way of doing this?

/// <summary>
/// <see cref="Process"/> extension methods.
/// </summary>
public static class Processes
{
    #region MailTo

    /// <summary>
    /// Populates the process with mailto <see cref="ProcessStartInfo"/>. You may leave any
    /// argument as <c>null</c> if not needed.
    /// </summary>
    /// <param name="process">The process.</param>
    /// <param name="mailMessage">The mail message.</param>
    public static void MailTo(this Process process, MailMessage mailMessage)
    {
        MailTo(
            process,
            mailMessage.To.ToDelimetedString(),
            mailMessage.CC.ToDelimetedString(),
            mailMessage.Bcc.ToDelimetedString(),
            mailMessage.Subject,
            mailMessage.Body);
    }

    /// <summary>
    /// Populates the process with mailto <see cref="ProcessStartInfo"/>. You may leave any
    /// argument as <c>null</c> if not needed.
    /// </summary>
    /// <param name="process">The process.</param>
    /// <param name="to">To email addresses.</param>
    public static void MailTo(this Process process, IEnumerable<string> to)
    {
        MailTo(
            process,
            to.ToDelimetedString(Character.SemiColon),
            null,
            null,
            null,
            null);
    }

    /// <summary>
    /// Populates the process with mailto <see cref="ProcessStartInfo"/>. You may leave any
    /// argument as <c>null</c> if not needed.
    /// </summary>
    /// <param name="process">The process.</param>
    /// <param name="to">To email addresses.</param>
    /// <param name="subject">The email subject.</param>
    public static void MailTo(this Process process, IEnumerable<string> to, string subject)
    {
        MailTo(
            process,
            to.ToDelimetedString(Character.SemiColon),
            null,
            null,
            subject,
            null);
    }

    /// <summary>
    /// Populates the process with mailto <see cref="ProcessStartInfo"/>. You may leave any
    /// argument as <c>null</c> if not needed.
    /// </summary>
    /// <param name="process">The process.</param>
    /// <param name="to">To email addresses.</param>
    /// <param name="subject">The email subject.</param>
    /// <param name="body">The email body.</param>
    public static void MailTo(
        this Process process,
        IEnumerable<string> to,
        string subject,
        string body)
    {
        MailTo(
            process,
            to.ToDelimetedString(Character.SemiColon),
            null,
            null,
            subject,
            body);
    }

    /// <summary>
    /// Populates the process with mailto <see cref="ProcessStartInfo"/>. You may leave any
    /// argument as <c>null</c> if not needed.
    /// </summary>
    /// <param name="process">The process.</param>
    /// <param name="to">To email addresses.</param>
    /// <param name="cc">The Cc email addresses.</param>
    /// <param name="subject">The email subject.</param>
    /// <param name="body">The email body.</param>
    public static void MailTo(
        this Process process,
        IEnumerable<string> to,
        IEnumerable<string> cc,
        string subject,
        string body)
    {
        MailTo(
            process,
            to.ToDelimetedString(Character.SemiColon),
            cc.ToDelimetedString(Character.SemiColon),
            null,
            subject,
            body);
    }

    /// <summary>
    /// Populates the process with mailto <see cref="ProcessStartInfo"/>. You may leave any 
    /// argument as <c>null</c> if not needed.
    /// </summary>
    /// <param name="process">The process.</param>
    /// <param name="to">To email addresses.</param>
    /// <param name="cc">The Cc email addresses.</param>
    /// <param name="bcc">The Bcc email addresses.</param>
    /// <param name="subject">The email subject.</param>
    /// <param name="body">The email body.</param>
    public static void MailTo(
        this Process process,
        IEnumerable<string> to,
        IEnumerable<string> cc,
        IEnumerable<string> bcc,
        string subject,
        string body)
    {
        MailTo(
            process,
            (to == null) ? null : to.ToDelimetedString(Character.SemiColon),
            (cc == null) ? null : cc.ToDelimetedString(Character.SemiColon),
            (bcc == null) ? null : bcc.ToDelimetedString(Character.SemiColon),
            subject,
            body);
    }

    /// <summary>
    /// Populates the process with mailto <see cref="ProcessStartInfo"/>. You may leave any
    /// argument as <c>null</c> if not needed.
    /// </summary>
    /// <param name="process">The process.</param>
    /// <param name="to">To email addresses.</param>
    /// <param name="cc">The Cc email addresses.</param>
    /// <param name="bcc">The Bcc email addresses.</param>
    /// <param name="subject">The email subject.</param>
    /// <param name="body">The email body.</param>
    /// <param name="attachmentPath">The attachment file path.</param>
    public static void MailTo(
        this Process process,
        IEnumerable<string> to,
        IEnumerable<string> cc,
        IEnumerable<string> bcc,
        string subject,
        string body,
        string attachmentPath)
    {
        MailTo(
            process,
            (to == null) ? null : to.ToDelimetedString(Character.SemiColon),
            (cc == null) ? null : cc.ToDelimetedString(Character.SemiColon),
            (bcc == null) ? null : bcc.ToDelimetedString(Character.SemiColon),
            subject,
            body,
            attachmentPath);
    }

    /// <summary>
    /// Populates the process with mailto <see cref="ProcessStartInfo"/>. You may leave any 
    /// argument as <c>null</c> if not needed.
    /// </summary>
    /// <param name="process">The process.</param>
    /// <param name="to">To email addresses delimeted by a semi-colon.</param>
    /// <param name="cc">The Cc email addresses delimeted by a semi-colon.</param>
    /// <param name="bcc">The Bcc email addresses delimeted by a semi-colon.</param>
    /// <param name="subject">The email subject.</param>
    /// <param name="body">The email body.</param>
    public static void MailTo(this Process process, string to, string cc, string bcc, string subject, string body)
    {
        MailTo(process, to, cc, bcc, subject, body, null);
    }

    /// <summary>
    /// Populates the process with mailto <see cref="ProcessStartInfo"/>. You may leave any
    /// argument as <c>null</c> if not needed.
    /// </summary>
    /// <param name="process">The process.</param>
    /// <param name="to">To email addresses delimeted by a semi-colon.</param>
    /// <param name="cc">The Cc email addresses delimeted by a semi-colon.</param>
    /// <param name="bcc">The Bcc email addresses delimeted by a semi-colon.</param>
    /// <param name="subject">The email subject.</param>
    /// <param name="body">The email body.</param>
    /// <param name="attachmentPath">The attachment file path. Note: this will not work in some 
    /// email applications.</param>
    public static void MailTo(
        this Process process,
        string to,
        string cc,
        string bcc,
        string subject,
        string body,
        string attachmentPath)
    {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.Append(Uri.UriSchemeMailto + Character.Colon);
        stringBuilder.Append(FormatMailToArgument(to));

        if (!string.IsNullOrEmpty(cc) || !string.IsNullOrEmpty(bcc) ||
            !string.IsNullOrEmpty(subject) || !string.IsNullOrEmpty(body) ||
            !string.IsNullOrEmpty(attachmentPath))
        {
            stringBuilder.Append(Character.Question);

            List<string> arguments = new List<string>();

            if (!string.IsNullOrEmpty(subject))
            {
                arguments.Add("subject=" + FormatMailToArgument(subject));
            }

            if (!string.IsNullOrEmpty(body))
            {
                arguments.Add("body=" + FormatMailToArgument(body));
            }

            if (!string.IsNullOrEmpty(cc))
            {
                arguments.Add("CC=" + FormatMailToArgument(cc));
            }

            if (!string.IsNullOrEmpty(bcc))
            {
                arguments.Add("BCC=" + FormatMailToArgument(bcc));
            }

            if (!string.IsNullOrEmpty(attachmentPath))
            {
                arguments.Add("attachment=" + FormatMailToArgument(attachmentPath));
            }

            stringBuilder.Append(arguments.ToDelimetedString(Character.Ampersand));
        }

        process.StartInfo = new ProcessStartInfo(stringBuilder.ToString());
    }

    #endregion

    #region Methods

    /// <summary>
    /// Formats the mailto argument. Converts <![CDATA['%', '&', ' ', '?', '\t', '\n']]> to their 
    /// hexadecimal representation.
    /// </summary>
    /// <param name="argument">The argument.</param>
    /// <returns>The formatted argument.</returns>
    private static string FormatMailToArgument(string argument)
    {
        return argument.
            Replace(Character.Percent.ToString(), "%25").
            Replace(Character.Ampersand.ToString(), "%26").
            Replace(Character.Colon.ToString(), "%3A").
            Replace(Character.HorizontalTab.ToString(), "%0D").
            Replace(Character.NewLine.ToString(), "%0A").
            Replace(Character.Question.ToString(), "%3F").
            Replace(Character.Quote.ToString(), "%22").
            Replace(Character.Space.ToString(), "%20");
    }

    #endregion
}

回答1:


If you mean is there are more efficient way to escape your email addresses then yes you could use the System.Uri class.

string escapedAddress = Uri.EscapeUriString("mailto:joe blogg's\r\n@mail.com");
Console.WriteLine(escapedAddress);

Output:

mailto:joe%20blogg's%0D%0A@mail.com

You'll notice in my example the single quote character doesn't get escaped but that's because it's not required to be in email addresses.

As far as the general approach you have used I don't see why you would add an extension method to the Process class. To send an email and have all the address escaping. attachments, server authentication etc. etc. taken care of why not just use the System.Net.Mail classes?




回答2:


As documented in is this official link, the EscapeUriString method assumes that stringToEscape parameter has no escape sequences in it.

This method is perfect for escaping Uris, but be careful because the target string is a mailto: line that can contain many parameters (not only subject, body, ...), obviously separated each one with some escape characters...like & and ?.

So, in my tests with Windows Store Apps with text taken from @anon comment, that string will not be fully escaped using just Uri.EscapeUriString() method, because it contains the escape sequence &.

You will need an extra manual escape to get the whole string be passed as parameter in a mailto: Uri:

Uri.EscapeUriString(stringToEscape).Replace("&", "%26");


来源:https://stackoverflow.com/questions/733899/c-sharp-start-a-new-mailto-process-and-html-url-encoding

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!