diff --git a/DESCRIPTION b/DESCRIPTION index 21724330..759aebe8 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -7,7 +7,8 @@ Authors@R: c( comment = c(ORCID = "0000-0003-3925-190X")), person("Joe", "Cheng", role = "aut", email = "joe@rstudio.com"), person("Jeroen", "Ooms", role = "ctb", email = "jeroen@berkeley.edu", - comment = c(ORCID = "0000-0002-4035-0289")) + comment = c(ORCID = "0000-0002-4035-0289")), + person("Salim", "Brüggemann", role = "ctb", email = "salim-b@pm.me") ) Description: Compose and send out responsive HTML email messages that render perfectly across a range of email clients and device sizes. Helper functions @@ -32,10 +33,12 @@ Imports: jsonlite (>= 1.6), magrittr (>= 1.5), mime (>= 0.6), + processx (>= 3.4.1), rlang (>= 0.4.1), rmarkdown, stringr (>= 1.4.0), - uuid (>= 0.1-2) + uuid (>= 0.1-2), + xfun (>= 0.11) Suggests: covr, ggplot2, @@ -48,7 +51,7 @@ Suggests: SystemRequirements: pandoc (>= 1.12.3) - http://pandoc.org Encoding: UTF-8 LazyData: true -RoxygenNote: 6.1.1 +RoxygenNote: 7.0.2 Roxygen: list(markdown = TRUE) VignetteBuilder: knitr Language: en-US diff --git a/NAMESPACE b/NAMESPACE index c17ee376..e10dc56b 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -28,6 +28,7 @@ export(creds_file) export(creds_key) export(get_html_str) export(md) +export(minify) export(prepare_rsc_example_files) export(prepare_test_message) export(render_connect_email) diff --git a/R/minify.R b/R/minify.R new file mode 100644 index 00000000..90adb45b --- /dev/null +++ b/R/minify.R @@ -0,0 +1,166 @@ +#' Minify an email +#' +#' Minify a blastula `email_message` object. +#' +#' The [minification](https://en.wikipedia.org/wiki/Minification_(programming)) +#' relies on the binary +#' [**minify**](https://github.com/tdewolff/minify/tree/master/cmd/minify) +#' which is cross-platform and works on Windows, macOS, Linux and BSD. +#' Pre-built binaries can be downloaded from +#' [here](https://github.com/tdewolff/minify/releases). Alternatively, +#' instructions to build minify from source are available +#' [here](https://github.com/tdewolff/minify/tree/master/cmd/minify#installation). +#' +#' @param email The email message object, as created by the [compose_email()] +#' function. The object's class is `email_message`. +#' @param binary_loc An option to supply the location of the `minify` +#' binary file should it not be on the system path or in the working +#' directory. +#' @param minify_opts A list of additional options to pass to the `minify` CLI +#' command. Only the following sensible subset of +#' [all possible minify options](https://github.com/tdewolff/minify/tree/master/cmd/minify#usage) +#' is supported, listed with their default values: +#' - \code{`html-keep-conditional-comments` = FALSE}: Preserve all IE conditional comments +#' - \code{`html-keep-default-attrvals` = FALSE}: Preserve default attribute values +#' - \code{`html-keep-document-tags` = FALSE}: Preserve ``, `` and `` tags +#' - \code{`html-keep-end-tags` = FALSE}: Preserve all end tags +#' - \code{`html-keep-quotes` = FALSE}: Preserve quotes around attribute values +#' - \code{`html-keep-whitespace` = FALSE}: Preserve whitespace characters but still collapse multiple into one +#' - \code{`css-decimals` = -1L}: Number of decimals to preserve in CSS numbers, +#' `-1L` means all +#' - \code{`svg-decimals` = -1L}: Number of decimals to preserve in SVG numbers, +#' `-1L` means all +#' - `verbose = FALSE`: Print informative messages about minification details. +#' @param echo If set to `TRUE`, the command to minify the `email_message` +#' object's HTML via `minify` will be printed to the console. By default, +#' this is `FALSE`. +#' +#' @examples +#' \donttest{# Create a simple test email +#' test_mail <- prepare_test_message() +#' +#' # Minify the test email +#' minify(test_mail) +#' +#' # The command used to minify can be printed +#' minify(email = test_mail, +#' echo = TRUE) +#' +#' # We can also provide options to the +#' # underlying minify command +#' minify(email = test_mail, +#' minify_opts = list(`html-keep-conditional-comments` = TRUE, +#' `html-keep-default-attrvals` = TRUE, +#' verbose = TRUE), +#' echo = TRUE) +#' } +#' +#' @return An `email_message` object. +#' @export +minify <- function(email, + binary_loc = NULL, + minify_opts = NULL, + echo = FALSE) { + + # Verify that the `email` object + # is of the class `email_message` + if (!inherits(email, "email_message")) { + stop("The object provided in `email` must be an ", + "`email_message` object.\n", + " * This can be created with the `compose_email()` function.", + call. = FALSE) + } + + # Determine the location of the `minify` binary + if (is.null(binary_loc)) { + binary_loc <- find_binary("minify") + if (is.null(binary_loc)) { + stop("The binary file `minify` is not in the system path or \n", + "in the working directory:\n", + " * download a pre-built binary from https://github.com/tdewolff/minify/releases\n", + " * or follow the installation instructions at https://github.com/tdewolff/minify/tree/master/cmd/minify#installation", + call. = FALSE) + } + } + + # Ensure provided minify options are valid + # and collect arguments and options for for `processx::run()` as a list + run_args <- character(0) + + if (!is.null(minify_opts)) { + binary_opts <- + c("html-keep-conditional-comments", + "html-keep-default-attrvals", + "html-keep-document-tags", + "html-keep-end-tags", + "html-keep-quotes", + "html-keep-whitespace", + "verbose") %>% + intersect(y = names(minify_opts)) + + int_opts <- + c("css-decimals", + "svg-decimals") %>% + intersect(y = names(minify_opts)) + + invalid_opts_i <- which( + !(names(minify_opts) %in% c(binary_opts, int_opts)) + ) + + if (length(invalid_opts_i) > 0) { + stop("Unknown options provided in `minify_opts`: ", names(minify_opts[invalid_opts_i]), + call. = FALSE) + } + + if (length(binary_opts) > 0) { + invalid_opts_i <- which( + names(minify_opts) %in% binary_opts & !sapply(minify_opts[binary_opts], is.logical) + ) + + if (length(invalid_opts_i) > 0) { + stop("The following `minify_opts` must be of type logical: ", + names(minify_opts[invalid_opts_i]), + call. = FALSE) + } + + run_args <- c(names(minify_opts[sapply(minify_opts, isTRUE)])) %>% paste0("--", .) + } + + if (length(int_opts) > 0) { + minify_opts[int_opts] <- as.integer(minify_opts[int_opts]) + + invalid_opts_i <- + names(minify_opts) %in% int_opts %>% + magrittr::and(!sapply(minify_opts[int_opts], + function(x) x >= -1L)) %>% + which() + + if (length(invalid_opts_i) > 0) { + stop("The following `minify_opts` must be >= -1: ", names(minify_opts[invalid_opts_i]), + call. = FALSE) + } + + run_args <- minify_opts[int_opts] %>% paste0(names(.), "=", .) + } + } + + # Write the inlined HTML message out to a file + # and remove the file after the function exits + tempfile_ <- tempfile(fileext = ".html") %>% tidy_gsub("\\\\", "/") + email$html_str %>% writeLines(con = tempfile_, useBytes = TRUE) + on.exit(file.remove(tempfile_)) + + # add input and file type + run_args <- c("--type=html", run_args, tempfile_) + + # Minify via `processx::run()` and assign the result + minify_result <- processx::run(command = binary_loc, + args = run_args, + echo_cmd = echo, + timeout = 60L) + + if (isTRUE(minify_opts$verbose)) message(minify_result$stderr) + + email$html_str <- minify_result$stdout + email +} diff --git a/R/utils.R b/R/utils.R index e0e8d242..daba7198 100644 --- a/R/utils.R +++ b/R/utils.R @@ -101,6 +101,66 @@ imgur_upload <- function(file, client_id) { ) } +#' An upgraded version of `Sys.which()` that returns a better Windows path +#' +#' @param name A single-length character vector with the executable name. +#' @noRd +sys_which <- function(name) { + + # Only accept a vector of length 1 + stopifnot(length(name) == 1) + + # Get the + if (xfun::is_windows()) { + + suppressWarnings({ + pathname <- + system(sprintf("where %s 2> NUL", name), intern = TRUE)[1] + }) + + if (!is.na(pathname)) { + + pathname <- pathname %>% tidy_gsub("\\\\", "/") + + return(stats::setNames(pathname, name)) + } + } + + Sys.which(name) %>% tidy_gsub("\\\\", "/") +} + +#' Find a binary on the system path or working directory +#' +#' @param bin_name The name of the binary to search for. +#' @noRd +find_binary <- function(bin_name) { + + # Find binary on path with `sys_which()` + which_result <- sys_which(name = bin_name) %>% unname() + + if (which_result != "") { + return(which_result) + } + + # Try to locate the binary in working directory + which_result <- + tryCatch( + { + processx::run(command = "ls", args = bin_name) + file.path(getwd(), bin_name) + }, + error = function(cond) "" + ) + + if (which_result != "") { + return(which_result) + } + + # If the binary isn't found in these locations, + # return `NULL` + NULL +} + # nocov end #' Prepend a element to a list at a given position diff --git a/man/add_attachment.Rd b/man/add_attachment.Rd index dd568a1f..b513995d 100644 --- a/man/add_attachment.Rd +++ b/man/add_attachment.Rd @@ -4,8 +4,12 @@ \alias{add_attachment} \title{Add a file attachment to an email message} \usage{ -add_attachment(email, file, content_type = mime::guess_type(file), - filename = basename(file)) +add_attachment( + email, + file, + content_type = mime::guess_type(file), + filename = basename(file) +) } \arguments{ \item{email}{The email message object, as created by the \code{\link[=compose_email]{compose_email()}} diff --git a/man/add_ggplot.Rd b/man/add_ggplot.Rd index 8c64e547..77c281aa 100644 --- a/man/add_ggplot.Rd +++ b/man/add_ggplot.Rd @@ -14,7 +14,7 @@ add_ggplot(plot_object, width = 5, height = 5, alt = NULL) \item{height}{The height of the output plot in inches.} \item{alt}{Text description of image passed to the \code{alt} attribute inside of -the image (\code{}) tag for use when image loading is disabled and on +the image (\verb{}) tag for use when image loading is disabled and on screen readers. Defaults to the \code{ggplot2} plot object's title, if exists. Override by passing a custom character string or \code{""} for no text.} } @@ -52,7 +52,7 @@ email <- "Hello! Here is a plot that will change -the way you look at cars forever.\\n", +the way you look at cars forever.\n", plot_html, "Let me know what you think about it!" diff --git a/man/add_image.Rd b/man/add_image.Rd index 4b6a506b..2623eeff 100644 --- a/man/add_image.Rd +++ b/man/add_image.Rd @@ -10,7 +10,7 @@ add_image(file, alt = NULL) \item{file}{A path to an image file.} \item{alt}{Text description of image passed to the \code{alt} attribute inside of -the image (\code{}) tag for use when image loading is disabled and on +the image (\verb{}) tag for use when image loading is disabled and on screen readers. \code{NULL} default produces blank (\code{""}) alt text.} } \value{ @@ -42,7 +42,7 @@ email <- c( "Hello, -Here is an image:\\n", +Here is an image:\n", img_file_html ) ) diff --git a/man/add_imgur_image.Rd b/man/add_imgur_image.Rd index bc244ca3..d5d9e86c 100644 --- a/man/add_imgur_image.Rd +++ b/man/add_imgur_image.Rd @@ -13,7 +13,7 @@ for which we'd like an image tag.} \item{client_id}{The Imgur Client ID value.} \item{alt}{Text description of image passed to the \code{alt} attribute inside of -the image (\code{}) tag for use when image loading is disabled and on +the image (\verb{}) tag for use when image loading is disabled and on screen readers. \code{NULL} default produces blank (\code{""}) alt text.} } \value{ @@ -26,13 +26,13 @@ the recipient) can be a harrowing experience. External images (i.e., available at public URLs) work exceedingly well and most email clients will faithfully display these images. With the \code{imgur_image()} function, we can take a local image file or a \code{ggplot2} plot object and send it to the Imgur -service, and finally receive an image (\code{}) tag that can be directly +service, and finally receive an image (\verb{}) tag that can be directly inserted into an email message using \code{compose_email()}. } \details{ To take advantage of this, we need to first have an account with Imgur and then obtain a \code{Client-ID} key for the Imgur API. This can be easily done by -going to \code{https://api.imgur.com/oauth2/addclient} and registering an +going to \verb{https://api.imgur.com/oauth2/addclient} and registering an application. Be sure to select the OAuth 2 authorization type without a callback URL. } diff --git a/man/add_readable_time.Rd b/man/add_readable_time.Rd index ef6c0b7a..d817ea63 100644 --- a/man/add_readable_time.Rd +++ b/man/add_readable_time.Rd @@ -4,8 +4,7 @@ \alias{add_readable_time} \title{Create a string with a more readable date/time} \usage{ -add_readable_time(time = NULL, use_date = TRUE, use_time = TRUE, - use_tz = TRUE) +add_readable_time(time = NULL, use_date = TRUE, use_time = TRUE, use_tz = TRUE) } \arguments{ \item{time}{The \code{POSIXct} time to use, and to make more readable for email diff --git a/man/attach_connect_email.Rd b/man/attach_connect_email.Rd index 31e187a1..dac1c50a 100644 --- a/man/attach_connect_email.Rd +++ b/man/attach_connect_email.Rd @@ -4,9 +4,14 @@ \alias{attach_connect_email} \title{Associate an email when publishing an R Markdown document to RStudio Connect} \usage{ -attach_connect_email(email = NULL, subject = NULL, - attachments = NULL, attach_output = FALSE, text = NULL, - preview = TRUE) +attach_connect_email( + email = NULL, + subject = NULL, + attachments = NULL, + attach_output = FALSE, + text = NULL, + preview = TRUE +) } \arguments{ \item{email}{A rendered email message. Normally, we'd want to use an diff --git a/man/blastula_email.Rd b/man/blastula_email.Rd index 4bb8b77d..5c436726 100644 --- a/man/blastula_email.Rd +++ b/man/blastula_email.Rd @@ -4,12 +4,26 @@ \alias{blastula_email} \title{The R Markdown \code{blastula_email} output format} \usage{ -blastula_email(toc = FALSE, toc_depth = 3, toc_float = FALSE, - number_sections = FALSE, section_divs = TRUE, fig_width = 5.35, - fig_height = 5, fig_retina = 2, fig_caption = TRUE, dev = "png", - smart = TRUE, self_contained = TRUE, template = "blastula", - includes = NULL, keep_md = FALSE, md_extensions = NULL, - connect_footer = FALSE, ...) +blastula_email( + toc = FALSE, + toc_depth = 3, + toc_float = FALSE, + number_sections = FALSE, + section_divs = TRUE, + fig_width = 5.35, + fig_height = 5, + fig_retina = 2, + fig_caption = TRUE, + dev = "png", + smart = TRUE, + self_contained = TRUE, + template = "blastula", + includes = NULL, + keep_md = FALSE, + md_extensions = NULL, + connect_footer = FALSE, + ... +) } \arguments{ \item{toc}{If you would like an automatically-generated table of contents in @@ -25,8 +39,8 @@ main document content. By default, this is \code{FALSE}.} \item{number_sections}{Sections can be sequentially numbered if this is set to \code{TRUE}. By default, this is \code{FALSE}.} -\item{section_divs}{This wraps sections in \code{
} tags and attaches -identifiers to the enclosing \code{
}s. This is set to \code{TRUE}.} +\item{section_divs}{This wraps sections in \verb{
} tags and attaches +identifiers to the enclosing \verb{
}s. This is set to \code{TRUE}.} \item{fig_width, fig_height}{The figure width and height in units of inches.} @@ -42,7 +56,7 @@ this is set to \code{TRUE}.} device.} \item{smart}{An option to produce typographically correct output. This will -convert straight quotes to curly quotes, \code{---} to em dashes, \code{--} to en +convert straight quotes to curly quotes, \verb{---} to em dashes, \verb{--} to en dashes, and instances of \code{...} to ellipses. By default, this is \code{TRUE}.} \item{self_contained}{Should a self-contained output file be generated. By diff --git a/man/block_articles.Rd b/man/block_articles.Rd index 3d0cef13..10eda349 100644 --- a/man/block_articles.Rd +++ b/man/block_articles.Rd @@ -14,7 +14,7 @@ With \code{block_articles()}, we can create a single- or multi-column layout of articles. The articles are responsive to the screen width, so side-by-side articles will collapse and any of the optional images will resize accordingly. The function can accept one to three \code{article()} calls, each -with varying amounts of text and imagery. Like all \code{block_*()} functions, +with varying amounts of text and imagery. Like all \verb{block_*()} functions, \code{block_articles()} must be placed inside of \code{blocks()} and the resultant \code{blocks} object can be provided to the \code{body}, \code{header}, or \code{footer} arguments of \code{compose_email()}. diff --git a/man/block_social_links.Rd b/man/block_social_links.Rd index 60cfc2c9..2d42cd8b 100644 --- a/man/block_social_links.Rd +++ b/man/block_social_links.Rd @@ -12,7 +12,7 @@ block_social_links(...) \description{ With \code{block_social_links()}, we can create a block of social sharing links and links to websites, email, or RSS feeds. The function can accept as many -\code{social_link()} calls as seen fit to email. Like all \code{block_*()} functions, +\code{social_link()} calls as seen fit to email. Like all \verb{block_*()} functions, \code{block_social_links()} must be placed inside of \code{blocks()} and the resultant \code{blocks} object can be provided to the \code{body}, \code{header}, or \code{footer} arguments of \code{compose_email()}. diff --git a/man/block_spacer.Rd b/man/block_spacer.Rd index a937e232..a7b28ec4 100644 --- a/man/block_spacer.Rd +++ b/man/block_spacer.Rd @@ -9,7 +9,7 @@ block_spacer() \description{ With \code{block_spacer()} we can more easily define an area of whitespace in a block-based layout. This function is meant to be easily combined with other -\code{block_*()} functions. Like all \code{block_*()} functions, \code{block_spacer()} must +\verb{block_*()} functions. Like all \verb{block_*()} functions, \code{block_spacer()} must be placed inside of \code{blocks()} and the resultant \code{blocks} object can be provided to the \code{body}, \code{header}, or \code{footer} arguments of \code{compose_email()}. } diff --git a/man/block_text.Rd b/man/block_text.Rd index 64287f3b..12f377ad 100644 --- a/man/block_text.Rd +++ b/man/block_text.Rd @@ -11,8 +11,8 @@ block_text(text) } \description{ With \code{block_text()} we can define a text area and this can be easily combined -with other \code{block_*()} functions. The text will take the entire width of the -block and will resize according to screen width. Like all \code{block_*()} +with other \verb{block_*()} functions. The text will take the entire width of the +block and will resize according to screen width. Like all \verb{block_*()} functions, \code{block_text()} must be placed inside of \code{blocks()} and the resultant \code{blocks} object can be provided to the \code{body}, \code{header}, or \code{footer} arguments of \code{compose_email()}. diff --git a/man/block_title.Rd b/man/block_title.Rd index c1a6cdbe..de6b8e98 100644 --- a/man/block_title.Rd +++ b/man/block_title.Rd @@ -11,9 +11,9 @@ block_title(title) } \description{ With \code{block_title()} we can define a title text area and this can be easily -combined with other \code{block_*()} functions. The title will take the entire +combined with other \verb{block_*()} functions. The title will take the entire width of the block and will resize according to screen width. Like all -\code{block_*()} functions, \code{block_title()} must be placed inside of \code{blocks()} +\verb{block_*()} functions, \code{block_title()} must be placed inside of \code{blocks()} and the resultant \code{blocks} object can be provided to the \code{body}, \code{header}, or \code{footer} arguments of \code{compose_email()}. } diff --git a/man/blocks.Rd b/man/blocks.Rd index 465ac4cf..9f1c0e16 100644 --- a/man/blocks.Rd +++ b/man/blocks.Rd @@ -7,10 +7,10 @@ blocks(...) } \arguments{ -\item{...}{One or more \code{block_*()} calls.} +\item{...}{One or more \verb{block_*()} calls.} } \description{ -To contain all of the block-based HTML \code{block_*()} calls, we should use +To contain all of the block-based HTML \verb{block_*()} calls, we should use the \code{blocks()} function. We can pass the resulting \code{blocks} object to either of the \code{body}, \code{header}, and \code{footer} arguments of \code{compose_email()}. } diff --git a/man/compose_email.Rd b/man/compose_email.Rd index 6122b909..8e345fed 100644 --- a/man/compose_email.Rd +++ b/man/compose_email.Rd @@ -4,14 +4,13 @@ \alias{compose_email} \title{Create the email message body} \usage{ -compose_email(body = NULL, header = NULL, footer = NULL, - title = NULL) +compose_email(body = NULL, header = NULL, footer = NULL, title = NULL) } \arguments{ \item{header, body, footer}{The three layout sections for an email message (ordered from top to bottom). Markdown text can be supplied to each of these by using the \code{\link[=md]{md()}} text helper function. Alternatively, we can -supply a set of \code{block_*()} calls enclosed within the \code{\link[=blocks]{blocks()}} function +supply a set of \verb{block_*()} calls enclosed within the \code{\link[=blocks]{blocks()}} function to take advantage of precomposed HTML blocks.} \item{title}{The title of the email message. This is not the subject but the diff --git a/man/create_smtp_creds_file.Rd b/man/create_smtp_creds_file.Rd index 95b83ad2..44afdd12 100644 --- a/man/create_smtp_creds_file.Rd +++ b/man/create_smtp_creds_file.Rd @@ -4,8 +4,14 @@ \alias{create_smtp_creds_file} \title{Store SMTP credentials in a file} \usage{ -create_smtp_creds_file(file, user = NULL, provider = NULL, - host = NULL, port = NULL, use_ssl = NULL) +create_smtp_creds_file( + file, + user = NULL, + provider = NULL, + host = NULL, + port = NULL, + use_ssl = NULL +) } \arguments{ \item{file}{The output filename for the credentials file.} diff --git a/man/create_smtp_creds_key.Rd b/man/create_smtp_creds_key.Rd index 8c7f7a39..ac30ee70 100644 --- a/man/create_smtp_creds_key.Rd +++ b/man/create_smtp_creds_key.Rd @@ -4,12 +4,18 @@ \alias{create_smtp_creds_key} \title{Store SMTP credentials in the system's key-value store} \usage{ -create_smtp_creds_key(id, user = NULL, provider = NULL, host = NULL, - port = NULL, use_ssl = NULL) +create_smtp_creds_key( + id, + user = NULL, + provider = NULL, + host = NULL, + port = NULL, + use_ssl = NULL +) } \arguments{ \item{id}{An identifying label for the keyname. The full key name is -constructed in the following way: \code{blastula-v1-}.} +constructed in the following way: \verb{blastula-v1-}.} \item{user}{The username for the email account. Typically, this is the email address associated with the account.} diff --git a/man/credential_helpers.Rd b/man/credential_helpers.Rd index 2a693100..c3c39265 100644 --- a/man/credential_helpers.Rd +++ b/man/credential_helpers.Rd @@ -8,11 +8,9 @@ \alias{creds_file} \title{Helpers for supplying SMTP credentials} \usage{ -creds(user = NULL, provider = NULL, host = NULL, port = NULL, - use_ssl = TRUE) +creds(user = NULL, provider = NULL, host = NULL, port = NULL, use_ssl = TRUE) -creds_anonymous(provider = NULL, host = NULL, port = NULL, - use_ssl = TRUE) +creds_anonymous(provider = NULL, host = NULL, port = NULL, use_ssl = TRUE) creds_key(id) diff --git a/man/minify.Rd b/man/minify.Rd new file mode 100644 index 00000000..0b2f0013 --- /dev/null +++ b/man/minify.Rd @@ -0,0 +1,75 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/minify.R +\name{minify} +\alias{minify} +\title{Minify an email} +\usage{ +minify(email, binary_loc = NULL, minify_opts = NULL, echo = FALSE) +} +\arguments{ +\item{email}{The email message object, as created by the \code{\link[=compose_email]{compose_email()}} +function. The object's class is \code{email_message}.} + +\item{binary_loc}{An option to supply the location of the \code{minify} +binary file should it not be on the system path or in the working +directory.} + +\item{minify_opts}{A list of additional options to pass to the \code{minify} CLI +command. Only the following sensible subset of +\href{https://github.com/tdewolff/minify/tree/master/cmd/minify#usage}{all possible minify options} +is supported, listed with their default values: +\itemize{ +\item \code{`html-keep-conditional-comments` = FALSE}: Preserve all IE conditional comments +\item \code{`html-keep-default-attrvals` = FALSE}: Preserve default attribute values +\item \code{`html-keep-document-tags` = FALSE}: Preserve \verb{}, \verb{} and \verb{} tags +\item \code{`html-keep-end-tags` = FALSE}: Preserve all end tags +\item \code{`html-keep-quotes` = FALSE}: Preserve quotes around attribute values +\item \code{`html-keep-whitespace` = FALSE}: Preserve whitespace characters but still collapse multiple into one +\item \code{`css-decimals` = -1L}: Number of decimals to preserve in CSS numbers, +\code{-1L} means all +\item \code{`svg-decimals` = -1L}: Number of decimals to preserve in SVG numbers, +\code{-1L} means all +\item \code{verbose = FALSE}: Print informative messages about minification details. +}} + +\item{echo}{If set to \code{TRUE}, the command to minify the \code{email_message} +object's HTML via \code{minify} will be printed to the console. By default, +this is \code{FALSE}.} +} +\value{ +An \code{email_message} object. +} +\description{ +Minify a blastula \code{email_message} object. +} +\details{ +The \href{https://en.wikipedia.org/wiki/Minification_(programming)}{minification} +relies on the binary +\href{https://github.com/tdewolff/minify/tree/master/cmd/minify}{\strong{minify}} +which is cross-platform and works on Windows, macOS, Linux and BSD. +Pre-built binaries can be downloaded from +\href{https://github.com/tdewolff/minify/releases}{here}. Alternatively, +instructions to build minify from source are available +\href{https://github.com/tdewolff/minify/tree/master/cmd/minify#installation}{here}. +} +\examples{ +\donttest{# Create a simple test email +test_mail <- prepare_test_message() + +# Minify the test email +minify(test_mail) + +# The command used to minify can be printed +minify(email = test_mail, + echo = TRUE) + +# We can also provide options to the +# underlying minify command +minify(email = test_mail, + minify_opts = list(`html-keep-conditional-comments` = TRUE, + `html-keep-default-attrvals` = TRUE, + verbose = TRUE), + echo = TRUE) +} + +} diff --git a/man/pipe.Rd b/man/pipe.Rd index 7e26451d..232f49ed 100644 --- a/man/pipe.Rd +++ b/man/pipe.Rd @@ -4,6 +4,6 @@ \alias{\%>\%} \title{The magrittr pipe} \description{ -The \code{blastula} package uses the pipe function, \code{\\\%>\\\%}, to turn function +The \code{blastula} package uses the pipe function, \verb{\\\%>\\\%}, to turn function composition into a series of imperative statements. } diff --git a/man/render_email.Rd b/man/render_email.Rd index 70adb8fc..8eba4f4c 100644 --- a/man/render_email.Rd +++ b/man/render_email.Rd @@ -5,12 +5,22 @@ \alias{render_connect_email} \title{R Markdown render functions for the \code{blastula_email} output format} \usage{ -render_email(input, envir = parent.frame(), quiet = TRUE, - output_options = list(), render_options = list()) +render_email( + input, + envir = parent.frame(), + quiet = TRUE, + output_options = list(), + render_options = list() +) -render_connect_email(input, connect_footer = TRUE, - envir = parent.frame(), quiet = TRUE, output_options = list(), - render_options = list()) +render_connect_email( + input, + connect_footer = TRUE, + envir = parent.frame(), + quiet = TRUE, + output_options = list(), + render_options = list() +) } \arguments{ \item{input}{The input file to be rendered. This should be an R Markdown diff --git a/man/send_by_mailgun.Rd b/man/send_by_mailgun.Rd index 2af11cf0..a46e6519 100644 --- a/man/send_by_mailgun.Rd +++ b/man/send_by_mailgun.Rd @@ -37,9 +37,9 @@ Mailgun. # # ## This a section heading # -# We can use Markdown formatting \\\\ -# to **embolden** text or to add \\\\ -# *emphasis*. This is exciting, \\\\ +# We can use Markdown formatting \\ +# to **embolden** text or to add \\ +# *emphasis*. This is exciting, \\ # right? # # Cheers") diff --git a/man/smtp_send.Rd b/man/smtp_send.Rd index 42cda775..3e71f1ad 100644 --- a/man/smtp_send.Rd +++ b/man/smtp_send.Rd @@ -4,8 +4,17 @@ \alias{smtp_send} \title{Send an email message through SMTP} \usage{ -smtp_send(email, to, from, subject = NULL, cc = NULL, bcc = NULL, - credentials = NULL, creds_file = "deprecated", verbose = FALSE) +smtp_send( + email, + to, + from, + subject = NULL, + cc = NULL, + bcc = NULL, + credentials = NULL, + creds_file = "deprecated", + verbose = FALSE +) } \arguments{ \item{email}{The email message object, as created by the \code{\link[=compose_email]{compose_email()}} @@ -46,7 +55,7 @@ store, through use of the \code{\link[=create_smtp_creds_key]{create_smtp_creds_ Such a file is created using the \code{\link[=create_smtp_creds_file]{create_smtp_creds_file()}} function.} \item{creds_file}{An option to specify a credentials file. As this argument -is deprecated, please consider using \code{credentials = creds_file()} +is deprecated, please consider using \verb{credentials = creds_file()} instead.} \item{verbose}{Should verbose output from the internal curl \code{send_mail()} diff --git a/man/social_link.Rd b/man/social_link.Rd index 2edb2544..c077aaec 100644 --- a/man/social_link.Rd +++ b/man/social_link.Rd @@ -16,7 +16,7 @@ social_link(service, link, variant = NULL, alt = NULL) and white, the default), \code{color}, \code{dark_gray}, \code{gray}, and \code{light_gray}.} \item{alt}{Text description of image passed to the \code{alt} attribute inside of -the image (\code{}) tag for use when image loading is disabled and on +the image (\verb{}) tag for use when image loading is disabled and on screen readers. If not supplied, then the name of the \code{service} will be used as alt text.} }