1
votes

I am writing a Rust application that will send email through an Exchange server with SMTP functionality enabled. According to Microsoft's webpage, the settings that are required are:

  • Server address smtp.office365.com
  • Port 587
  • StartTLS Enabled
  • Credentials for mail account login

These are corroborated by the POP/IMAP settings of the webmail service.

Here is my code (with some censoring):

extern crate lettre;

use self::lettre::email::EmailBuilder;
use self::lettre::transport::smtp::{SecurityLevel, SmtpTransportBuilder, SUBMISSION_PORT};
use self::lettre::transport::smtp::authentication::Mechanism;
use self::lettre::transport::EmailTransport;

pub fn send_mail() {
    let email = EmailBuilder::new()
        .from("my email")
        .to("destination email")
        .body("testing")
        .subject("testing")
        .build()
        .unwrap();

    // Connect to SMTP server
    let mut transport = SmtpTransportBuilder::new(("smtp.office365.com", SUBMISSION_PORT))
        .expect("Failed to create email transport")
        .encrypt()
        .smtp_utf8(true)
        .credentials("my email", "my password")
        .authentication_mechanism(Mechanism::Login)
        .build();
    println!("Mail transport built");

    println!("{:?}", transport.send(email.clone()));
}

When I compile and run the code,it gives me this error:

Err(Permanent(Response { code: Code { severity: PermanentNegativeCompletion, category: Unspecified3, detail: 0 }, message: ["5.7.57 SMTP; Client was not authenticated to send anonymous mail during MAIL FROM [SYXPR01CA0106.ausprd01.prod.outlook.com]"] }))

Why is this happening?

The closest I've come in my research is an issue on GitHub in relation to the lettre library not supporting the Login authentication mechanism (which Office 365 uses); however, the codebase was updated to support Login and I am using the master branch directly from GitHub so theoretically my application should support the Login mechanism.

Edit: Forgot to mention that I attempted an EHLO to the server, but it returned a (Client:(Connection closed)) error.

1
@FrancoisMockers Yes, my email credentials are in the code, I will try using some alternative credentials to see if it works. If that doesn't work, I'll try the password changing method, and then after that I'll go back to trying different settings with the transport. Thanks for the link.foggy0400
I solved it! I used telnet and openssl to try connecting directly to my SMTP server, where I found that AUTH LOGIN requires 3 commands; one to send the AUTH LOGIN code, one to send the username and another to send the password. Turns out the lettre library implements all its AUTH commands as single commands, so this wasn't working with the server. I downloaded the source code for the library, changed the send function to do the three separate commands, recompiled my code and everything worked fine :)foggy0400

1 Answers

0
votes

I used telnet and openssl to try connecting directly to my SMTP server, where I found that AUTH LOGIN requires 3 commands; one to send the AUTH LOGIN code, one to send the username and another to send the password. I found that the lettre library implements all its AUTH commands as single commands, so this wasn't working with the server. I downloaded the source code for the library, changed the send function to do the three separate commands, recompiled my code and everything worked fine :)

My addition to the lettre code:

if (accepted_mechanisms[0] == Mechanism::Login) &&
            (accepted_mechanisms.capacity() == 1) {
            try_smtp!(self.client.command("AUTH LOGIN"), self);
            try_smtp!(self.client.command(base64::encode_config(
                                            &username.as_bytes(),
                                            base64::STANDARD).as_str()), self);
            try_smtp!(self.client.command(base64::encode_config(
                                                        &password.as_bytes(),
                                                        base64::STANDARD).as_str()), self);