rstudio / blastula

Easily send great-looking HTML email messages from R
https://pkgs.rstudio.com/blastula
Other
544 stars 84 forks source link

SMTP without username/password #237

Open doncqueurs opened 3 years ago

doncqueurs commented 3 years ago

I am provided with an SMTP solution that does not require a username and password and I would like to use this in combination with Blastula. This sounds very unsafe, but the IP address of the server is fixed.

Details about the SMPT solution can be found at the following page (option 3): https://docs.microsoft.com/en-us/exchange/mail-flow-best-practices/how-to-set-up-a-multifunction-device-or-application-to-send-email-using-microsoft-365-or-office-365#option-3-configure-a-connector-to-send-mail-using-microsoft-365-or-office-365-smtp-relay

When I try to create a creds_file it prompts me with the SMTP password request. Anyway to get around this?

doncqueurs commented 3 years ago

I found a way to get it working by adjusting some of the functions in the package. You may want to consider this as inspiration for implementing this as a change in the package. In essence what I did was commenting out everything related to the password. I had to create a couple of tiles to run it outside the package.

Here is the code that worked for me:

create_credentials_list_no_pw <- function(provider,
                                    user,
                                    host,
                                    port,
                                    use_ssl) {

  creds_internal_no_pw(
    user = user,
    provider = provider,
    host = host,
    port = port,
    use_ssl = use_ssl
  )
}

create_smtp_creds_file_no_pw <- function(file,
                                   user = NULL,
                                   provider = NULL,
                                   host = NULL,
                                   port = NULL,
                                   use_ssl = NULL) {

  # nocov start

  # Use an empty string for `user` if NULL
  if (is.null(user)) user <- ""

  # Create a credentials list from the function inputs
  credentials_list <-
    create_credentials_list_no_pw(
      provider = provider,
      user = user,
      host = host,
      port = port,
      use_ssl = use_ssl
    )

  # Create a plaintext JSON string for the credentials
  serialized <- JSONify_credentials(credentials_list)

  # Write the credential values into a plaintext file
  # that contains JSON
  writeLines(serialized, file)
  Sys.chmod(file, mode = "0600")

  # Issue a message stating that the file has been created
  message("The SMTP credentials file (`", file, "`) has been generated")

  # nocov end
}

creds_internal_no_pw <- function(user = NULL,
                           # password = NULL,
                           provider = NULL,
                           host = NULL,
                           port = NULL,
                           use_ssl = NULL) {

  # If a `provider` name is given, extract values for `host`,
  # `port`, `use_ssl`, `use_tls`, and `authenticate`
  if (!is.null(provider)) {

    validate_smtp_provider(provider = provider)

    # Extract the record for the SMTP provider
    smtp_settings <- get_smtp_provider_values(provider = provider)

    # Extract settings for the provider
    if (is.null(host)) host <- smtp_settings$server
    if (is.null(port)) port <- smtp_settings$port
    if (is.null(use_ssl)) use_ssl <- smtp_settings$use_ssl
  }

  if (any(is.null(host), is.null(port), is.null(use_ssl))) {
    stop("The `host`, `port`, and `use_ssl` SMTP options must be provided ",
         "with values.", call. = FALSE)
  }

  # Generate the credentials list
  list(
    version = schema_version,
    host = host,
    port = port,
    use_ssl = use_ssl,
    user = user#,
    # password = password
  )
}

schema_version <- 1L

JSONify_credentials <- function(credentials_list) {

  # Create a plaintext JSON string for the credentials
  credentials_list %>%
    jsonlite::serializeJSON() %>%
    as.character()
}

create_smtp_creds_file_no_pw(
  "smtp_creds_file_server",
  host = "[domain_com].mail.protection.outlook.com",
  port = 25,
  use_ssl = TRUE
)
rich-iannone commented 3 years ago

Thanks for exploring this. This is something we thought about awhile back, but we weren't able to test it on an SMTP server that allowed for no password. Question: what does pressing ENTER on the password prompt do? We were thinking that was an empty string but perhaps it isn't valid input?

doncqueurs commented 3 years ago

Pressing ENTER on the password prompt bounces back an error pop-up with the text: "You must enter a value". The only way out of the prompt is pressing Cancel.

rich-iannone commented 3 years ago

Ah! That's exactly what we don't want, okay we will fix that (and include some explanatory text).

beansrowning commented 3 years ago

I've also accomplished this by making a psuedo blastula_creds object with no username and password, since this is not checked in smtp_send() if passed via the credentials argument FWIU.

library(blastula)

email <- render_email("summarize.Rmd")

blastula_creds <- structure(
  list(host = "my_host.com", port = 25, use_ssl = TRUE),
  class = "blastula_creds"
)

smtp_send(
  email,
  to = readLines("recipients.conf"),
  from = "my_email@my_host.com",
  subject = sprintf("%s Report", as.character(Sys.Date())),
  credentials = blastula_creds
)

Your results may vary.

shrektan commented 3 years ago

Not sure if it's related but I needed the same functionality (no username and password) in smtp_send() recently. And my solution is to use blastula::creds_anonymous() as the credentials.

beansrowning commented 3 years ago

Yes, that seems to be the intended solution. Should have dug around in the man pages a bit more. If this is a common use case, maybe it's worth documenting it explicitly?

tylerlittlefield commented 3 years ago

@shrektan Using blastula::creds_anonymous() worked perfectly for me, thanks!

indykpol commented 2 years ago

Not sure if it's related but I needed the same functionality (no username and password) in smtp_send() recently. And my solution is to use blastula::creds_anonymous() as the credentials.

Bingo! thanks @shrektan.