sendmailR/0000755000176200001440000000000014357751432012203 5ustar liggesuserssendmailR/NAMESPACE0000644000176200001440000000060114356134171013411 0ustar liggesusers# Generated by roxygen2: do not edit by hand S3method(mime_part,character) S3method(mime_part,data.frame) S3method(mime_part,default) S3method(mime_part,ggplot) S3method(mime_part,matrix) S3method(mime_part,trellis) export(mime_part) export(mime_part_html) export(sendmail) export(sendmailOptions) export(sendmail_options) importFrom(base64enc,base64encode) importFrom(grDevices,pdf) sendmailR/README.md0000644000176200001440000000333614357517542013471 0ustar liggesusers# sendmailR [![OSS Lifecycle](https://img.shields.io/osslifecycle/olafmersmann/sendmailR)](https://lifecycle.r-lib.org/articles/stages.html) [![CRAN status](https://www.r-pkg.org/badges/version/sendmailR)](https://CRAN.R-project.org/package=sendmailR) [![CRAN Downloads](http://cranlogs.r-pkg.org/badges/sendmailR)](https://CRAN.R-project.org/package=sendmailR) [![CRAN Downloads](http://cranlogs.r-pkg.org/badges/grand-total/sendmailR)](https://CRAN.R-project.org/package=sendmailR) Package contains a simple SMTP client with minimal dependencies which provides a portable solution for sending email, including file attachments and inline html reports, from within [R](https://www.r-project.org/). SMTP Authentication and SSL/STARTTLS is implemented using curl. ## Usage ``` r from <- sprintf("", Sys.info()[4]) to <- "" subject <- "Hello from R" body <- list("It works!", mime_part(iris)) sendmail(from, to, subject, body, control=list(smtpServer="ASPMX.L.GOOGLE.COM")) # With authentication and SSL sendmail(from="from@example.org", to=c("to1@example.org","to2@example.org"), subject="SMTP auth test", msg=mime_part("This message was send using sendmailR and curl."), engine = "curl", engineopts = list(username = "foo", password = "bar"), control=list(smtpServer="smtp://smtp.gmail.com:587", verbose = TRUE) ) ``` ## Install from github To install the bleeding edge version from GitHub using [`devtools`](https://github.com/r-lib/devtools): ```splus library("devtools") install_github("olafmersmann/sendmailR") ``` Or using [`pak`](https://github.com/r-lib/pak): ```splus library("pak") pkg_install("olafmersmann/sendmailR") ``` sendmailR/man/0000755000176200001440000000000014357517542012760 5ustar liggesuserssendmailR/man/mime_part.Rd0000644000176200001440000000127414356134171015220 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/mime_part.R \name{mime_part} \alias{mime_part} \title{Create a MIME part} \usage{ mime_part(x, name, ...) } \arguments{ \item{x}{Object to include} \item{name}{Name of mime part. Usually the filename of the attachment as displayed by the e-mail client.} \item{...}{Possible further arguments for \code{mime_part} implementations.} } \value{ An S3 \code{mime_part} object. } \description{ Create a MIME part } \seealso{ \code{\link{mime_part.character}}, \code{\link{mime_part_html}}, \code{\link{mime_part.data.frame}}, \code{\link{mime_part.matrix}}, \code{\link{mime_part.ggplot}}, \code{\link{mime_part.trellis}} } sendmailR/man/mime_part.matrix.Rd0000644000176200001440000000071514303161524016514 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/mime_part.R \name{mime_part.matrix} \alias{mime_part.matrix} \title{Create a MIME part from a matrix.} \usage{ \method{mime_part}{matrix}(x, name = deparse(substitute(x)), ...) } \arguments{ \item{x}{Matrix} \item{name}{Basename of file attachment that is generated.} \item{...}{Ignored.} } \value{ An S3 \code{mime_part} object } \description{ Create a MIME part from a matrix. } sendmailR/man/mime_part_html.Rd0000644000176200001440000000163114356134171016241 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/mime_part.R \name{mime_part_html} \alias{mime_part_html} \title{Create an inline HTML MIME Part} \usage{ mime_part_html(x, ...) } \arguments{ \item{x}{Character string, vector/list of character strings or path to html file.} \item{...}{Ignored.} } \value{ An S3 \code{mime_part} object. } \description{ Create a MIME part from a character string containing HTML. If the string matches a filename the file is read and inserted as an inline character MIME part. } \examples{ \dontrun{ sendmail( from="from@example.org", to="to1@example.org", subject="inline HTML", msg=mime_part_html("Hello
World"), control=list(smtpServer="ASPMX.L.GOOGLE.COM") ) sendmail( from="from@example.org", to="to1@example.org", subject="inline HTML", msg=mime_part_html("out/report.html"), control=list(smtpServer="ASPMX.L.GOOGLE.COM") ) } } sendmailR/man/mime_part.character.Rd0000644000176200001440000000143114356134171017146 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/mime_part.R \name{mime_part.character} \alias{mime_part.character} \title{Create an inline character MIME Part} \usage{ \method{mime_part}{character}(x, name, type = "text/plain", flowed = FALSE, ...) } \arguments{ \item{x}{Character string, possibly a filename.} \item{name}{Name of attachment.} \item{type}{Content type of inline text. Defaults to "text/plain".} \item{flowed}{Should "format=flowed" be added to the content header.} \item{...}{Ignored.} } \value{ An S3 \code{mime_part} object. } \description{ Create a MIME part from a character string. If the string matches a filename, a MIME part containing that file is returned instead. } \seealso{ \code{\link{mime_part_html}} for adding inline HTML } sendmailR/man/mime_part.default.Rd0000644000176200001440000000103214303161524016625 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/mime_part.R \name{mime_part.default} \alias{mime_part.default} \title{Default MIME part method} \usage{ \method{mime_part}{default}(x, name, ...) } \arguments{ \item{x}{R object} \item{name}{Filename used for attachment (sans the .R extension)} \item{...}{Ignored.} } \value{ An S3 \code{mime_part} object. } \description{ Creates a string representation of the object \code{x} using \code{dput}. This representation is then turned into a file attachment. } sendmailR/man/mime_part.ggplot.Rd0000644000176200001440000000120514303161524016477 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/mime_part.R \name{mime_part.ggplot} \alias{mime_part.ggplot} \title{Creates a MIME part from a ggplot2 plot object} \usage{ \method{mime_part}{ggplot}(x, name = deparse(substitute(x)), device = pdf, ...) } \arguments{ \item{x}{A \code{ggplot} object} \item{name}{Name of attachment (sans .pdf extension).} \item{device}{Graphics device used to render the plot. Defaults to \code{pdf}.} \item{...}{Ignored.} } \value{ An S3 \code{mime_part} object. } \description{ Writes a PDF file of the plot defined by \code{x} and turns this PDF file into a file attachment. } sendmailR/man/mime_part.trellis.Rd0000644000176200001440000000122314303161524016661 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/mime_part.R \name{mime_part.trellis} \alias{mime_part.trellis} \title{Creates a MIME part from a trellis plot object} \usage{ \method{mime_part}{trellis}(x, name = deparse(substitute(x)), device = pdf, ...) } \arguments{ \item{x}{A \code{trellis} (lattice) object} \item{name}{Name of attachment (sans .pdf extension).} \item{device}{Graphics device used to render the plot. Defaults to \code{pdf}.} \item{...}{Ignored.} } \value{ An S3 \code{mime_part} object. } \description{ Writes a PDF file of the plot defined by \code{x} and turns this PDF file into a file attachment. } sendmailR/man/mime_part.data.frame.Rd0000644000176200001440000000117714303161524017215 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/mime_part.R \name{mime_part.data.frame} \alias{mime_part.data.frame} \title{Create a MIME part from a \code{data.frame}.} \usage{ \method{mime_part}{data.frame}(x, name = deparse(substitute(x)), filename_extension = ".txt", ...) } \arguments{ \item{x}{A \code{data.frame}.} \item{name}{Basename of file attachment that is generated.} \item{filename_extension}{Filename extension (i.e., the suffix) to be used for the attached file.} \item{...}{Ignored.} } \value{ An S3 \code{mime_part} object. } \description{ Create a MIME part from a \code{data.frame}. } sendmailR/man/sendmail.Rd0000644000176200001440000000465414357575423015056 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/sendmailR.r \name{sendmail} \alias{sendmail} \title{Send mail from within R} \usage{ sendmail( from, to, subject, msg, cc, bcc, ..., engine = c("internal", "curl", "debug"), headers = list(), control = list(), engineopts = list() ) } \arguments{ \item{from}{From whom the mail message is (RFC2822 style address).} \item{to}{Recipient of the message (vector of valid RFC2822 style addresses).} \item{subject}{Subject line of message.} \item{msg}{Body text of message or a list containing \code{\link{mime_part}} objects.} \item{cc}{Carbon-copy recipients (vector of valid RFC2822 style addresses).} \item{bcc}{Blind carbon-copy recipients (vector of valid RFC2822 style addresses).} \item{\dots}{...} \item{engine}{One of: \itemize{ \item{\code{"internal"} for the internal smtp transport (default).} \item{\code{"curl"} for the use of curl for transport. Enable if you need STARTTLS/SSL and/or SMTP authentication. See \code{curl::\link[curl]{send_mail}}.} \item{\code{"debug"} sendmail returns a RFC2822 formatted email message without sending it.} }} \item{headers}{Any other headers to include.} \item{control}{List of SMTP server settings. Valid values are the possible options for \code{\link{sendmail_options}}.} \item{engineopts}{Options passed to curl if using the curl backend. \itemize{ \item{For authentication pass a list with \code{username} and \code{password}.} \item{\code{use_ssl} defaults to "force" if unset.} \item{For available options run \code{curl::\link[curl]{curl_options}}.} }} } \description{ Simplistic sendmail utility for R. Uses SMTP to submit a message to a local SMTP server. } \examples{ \dontrun{ from <- sprintf("", Sys.info()[4]) to <- "" subject <- "Hello from R" body <- list("It works!", mime_part(iris)) sendmail(from, to, subject, body, control=list(smtpServer="ASPMX.L.GOOGLE.COM")) sendmail(from="from@example.org", to=c("to1@example.org", "to2@example.org"), subject="SMTP auth test", msg=mime_part("This message was send using sendmailR and curl."), engine = "curl", engineopts = list(username = "foo", password = "bar"), control=list(smtpServer="smtp://smtp.gmail.com:587", verbose = TRUE) ) } } \seealso{ \code{\link{mime_part}} for a way to add attachments. \code{curl::\link[curl]{send_mail}} for curl SMTP URL specification. } \keyword{utilities} sendmailR/man/sendmail_options.Rd0000644000176200001440000000262114303161524016601 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/options.R \name{sendmail_options} \alias{sendmail_options} \alias{sendmailOptions} \title{Set package specific options.} \usage{ sendmail_options(...) sendmailOptions(...) } \arguments{ \item{...}{Any options can be defined, using \code{name=value} or by passing a list of such tagged values. However, only the ones below are used in base sendmailR.} } \value{ For \code{sendmail_options()}, a list of all set options sorted by name. For \code{sendmail_options(name)}, a list of length one containing the set value, or 'NULL' if it is unset. For uses setting one or more options, a list with the previous values of the options changed (returned invisibly). } \description{ Specify global sendmail options so that subsequent calls to \code{sendmail()} do not have to set them in the \code{control} argument. } \details{ List of options: \itemize{ \item{smtpServer}{SMTP server to contact. This can either be the mail server responsible for the destination addresses domain or a smarthost provided by your ISP or institution. SMTP AUTH is currently unsupported.} \item{smtpPort}{SMTP port to use. Usually 25 but some institutions require the use of the submission service (port 587).} \item{verbose}{Show detailed information about message submission. Useful for debugging.} } } \author{ Olaf Mersmann \email{olafm@datensplitter.net} } sendmailR/DESCRIPTION0000644000176200001440000000314314357751432013712 0ustar liggesusersPackage: sendmailR Version: 1.4-0 Title: Send Email Using R Description: Package contains a simple SMTP client with minimal dependencies which provides a portable solution for sending email, including file attachments and inline html reports, from within R. SMTP Authentication and SSL/STARTTLS is implemented using curl. Authors@R: c( person("Olaf", "Mersmann", role=c("aut", "cre"), comment = c(ORCID = "0000-0002-7720-4939"), email = "olafm@p-value.net"), person("Quinn", "Weber", role="ctb"), person("Marius", "Barth", role = "ctb", comment = c(ORCID = "0000-0002-3421-6665")), person("Are", "Edvardsen", role = "ctb", comment = c(ORCID = "0000-0002-5210-3656")), person("Alexander", "Bartel", role = "ctb", comment = c(ORCID = "0000-0002-1280-6138")) ) URL: https://github.com/olafmersmann/sendmailR BugReports: https://github.com/olafmersmann/sendmailR/issues Depends: R (>= 3.0.0) Imports: base64enc Suggests: curl (>= 4.0), knitr, rmarkdown, htmltools License: GPL-2 Encoding: UTF-8 RoxygenNote: 7.2.3 VignetteBuilder: knitr NeedsCompilation: no Packaged: 2023-01-11 18:18:37 UTC; olafm Author: Olaf Mersmann [aut, cre] (), Quinn Weber [ctb], Marius Barth [ctb] (), Are Edvardsen [ctb] (), Alexander Bartel [ctb] () Maintainer: Olaf Mersmann Repository: CRAN Date/Publication: 2023-01-12 09:30:02 UTC sendmailR/build/0000755000176200001440000000000014357576575013317 5ustar liggesuserssendmailR/build/vignette.rds0000644000176200001440000000037514357576575015663 0ustar liggesusersmQMk0 u>֭0@z( FC"V) _NYȖ{OOx7QJ*'R&S9FJX'= ʹcgJ t804̘Y2ih a @ipnauFK?֍Ŋ| uP鳩]Ϲ:L2%smhzҿ?vu;ܷ%I"\4/чN42f{'sÚ sendmailR/tests/0000755000176200001440000000000014356134171013337 5ustar liggesuserssendmailR/tests/multiple_recipients.R0000644000176200001440000000513214356134171017543 0ustar liggesuserslibrary("sendmailR") sendmail(from="from@example.org", to="to1@example.org", subject="foo", msg="bar", control=list(transport="debug")) sendmail(from="from@example.org", to=c("to1@example.org", "to2@example.org"), subject="foo", msg="bar", control=list(transport="debug")) sendmail(from="from@example.org", to=c("to1@example.org", "to2@example.org"), cc="cc1@example.org", subject="foo", msg="bar", control=list(transport="debug")) sendmail(from="from@example.org", to=c("to1@example.org", "to2@example.org"), cc="cc1@example.org", subject="foo", msg="bar", control=list(transport="debug")) sendmail(from="from@example.org", to="to1@example.org", cc=c("cc1@example.org", "cc2@example.org"), subject="foo", msg="bar", control=list(transport="debug")) sendmail(from="from@example.org", to="to1@example.org", bcc="bcc1@example.org", subject="foo", msg="bar", control=list(transport="debug")) sendmail(from="from@example.org", to="to1@example.org", bcc=c("bcc1@example.org", "bcc2@example.org"), subject="foo", msg="bar", control=list(transport="debug")) ## Subject encoding sendmail(from="from@example.org", to="to1@example.org", subject="K\u00f6ln", msg="bar", control=list(transport="debug")) ## Character MIME part encoding sendmail(from="from@example.org", to="to1@example.org", subject="UTF-8 test", msg=mime_part(c("test", "tεst", "täst", "tëst", "的", "؈")), control=list(transport="debug")) sendmail(from="from@example.org", to="to1@example.org", subject="UTF-8 test", msg=mime_part(c("test", "tεst", "täst", "tëst", "的", "؈"), flowed = TRUE), control=list(transport="debug")) sendmail(from="from@example.org", to="to1@example.org", subject="latin1 test", msg=mime_part(iconv("täst", to = "latin1")), control=list(transport="debug")) ## Inline HMTL MIME part sendmail(from="from@example.org", to="to1@example.org", subject="Simple inline HTML", msg=mime_part_html("a
b"), control=list(transport="debug")) sendmail(from="from@example.org", to="to1@example.org", subject="Inline HTML from file", msg=mime_part_html(system.file("afm/MustRead.html", package = "grDevices")), control=list(transport="debug")) sendmailR/vignettes/0000755000176200001440000000000014357576575014230 5ustar liggesuserssendmailR/vignettes/sending-html-reports.Rmd0000644000176200001440000000445314357517542020754 0ustar liggesusers--- title: "Sending HTML reports inline and as attachment created with knitr" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Sending HTML reports inline and as attachment created with knitr} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r echo = FALSE} knitr::opts_chunk$set(collapse = TRUE, comment = "#>", fig.width = 7, fig.height = 5, warning = FALSE, message = FALSE) if (!requireNamespace("rmarkdown", quietly = TRUE) || !requireNamespace("htmltools", quietly = TRUE)) { knitr::opts_chunk$set(eval = FALSE, tidy = FALSE) } ``` This file shows a typical workflow for knitting *.Rmd* documents and sending them per E-Mail. First we have our **my_file.Rmd** which looks like this: ````{=html}
---
title: ' '
output: 
  html_document:
    theme: null
    highlight: null
    mathjax: null
---

Hello everyone,\n

here is a calculation.

**2+2 =**

`​``{r echo=FALSE}
2+2
`​``

All the best
```` ```{r include=FALSE} test.Rmd <- "--- title: ' ' output: html_document: theme: null highlight: null mathjax: null --- Hello everyone,\n here is a calculation. **2+2 =** \```{r echo=FALSE} 2+2 \``` All the best " writeLines(test.Rmd, con = "my_file.Rmd") ``` ## Render your rmarkdown file ```{r echo=TRUE, results = 'hide'} htmlout <- tempfile(fileext = ".html") rmarkdown::render( input = "my_file.Rmd", intermediates_dir = ".", output_file = htmlout, ) ``` ## This is the resulting HTML document ```{r echo=FALSE, results='asis'} unlink("my_file.Rmd") htmltools::includeHTML(htmlout) ``` ------------------------------------------------------------------------ ## Sending the html file per E-Mail We can now send the the resulting html file as A) an file attachment or B) inline HTML. ### A) File attachment ```{r} library(sendmailR) sendmail(from="from@example.org", to="to1@example.org", subject="File attachment", msg=c( mime_part("Hello everyone,\n here is the newest report.\n Bye"), mime_part(htmlout, name = "report.html")), engine = "debug") ``` ### B) Inline HTML ```{r message=TRUE} sendmail(from="from@example.org", to="to1@example.org", subject="Inline HTML", msg=mime_part_html(htmlout), engine = "debug") ``` sendmailR/R/0000755000176200001440000000000014357517542012406 5ustar liggesuserssendmailR/R/sendmailR.r0000644000176200001440000002345214357517542014515 0ustar liggesusers## ## sendmailR.r - send email from within R ## ## Author: ## Olaf Mersmann (OME) ## .rfc2822_date <- function(time=Sys.time()) { lc <- Sys.getlocale("LC_TIME") on.exit(Sys.setlocale("LC_TIME", lc)) Sys.setlocale("LC_TIME", "C") strftime(time, format="%a, %d %b %Y %H:%M:%S -0000", tz="UTC", use.tz=TRUE) } .rfc2047_subject <- function(subject) { subject <- enc2utf8(subject) prefix <- "=?" charset <- "UTF-8?" encoding <- "B?" suffix <- "?=" subject <- charToRaw(subject) subject <- base64enc::base64encode(subject, linewidth = 63) paste(paste0(prefix, charset, encoding, subject, suffix), collapse = " ") } .get_recipients <- function(headers) { # TODO: parse e-mail from "name " res <- headers$To if (!is.null(headers$Cc)) { res <- c(res, headers$Cc) } if (!is.null(headers$Bcc)) { res <- c(res, headers$Bcc) } res } .write_mail <- function(headers, msg, sock) { if (!is.list(msg)) msg <- list(msg) ## Generate MIME headers: boundary <- paste(packBits(sample(0:1, 256, TRUE)), collapse="") headers$`MIME-Version` <- "1.0" headers$`Content-Type` <- sprintf("multipart/mixed; boundary=\"%s\"", boundary) headers$To <- paste(headers$To, collapse=", ") if (!is.null(headers$Cc)) headers$Cc <- paste(headers$Cc, collapse=", ") ## Do not include BCC recipients in headers, after all, it is a ## _blind_ carbon-copy. headers$Bcc <- NULL writeLines(paste(names(headers), unlist(headers), sep=": "), sock, sep="\r\n") writeLines("", sock, sep="\r\n") writeLines("This is a message with multiple parts in MIME format.", sock, sep="\r\n") for (part in msg) { writeLines(sprintf("--%s", boundary), sock, sep="\r\n") if (inherits(part, "mime_part")) .write_mime_part(part, sock) else if (is.character(part)) { ## Legacy support for plain old string ## writeLines(sprintf("--%s", boundary), sock, sep="\r\n") writeLines("Content-Type: text/plain; format=flowed\r\n", sock, sep="\r\n") writeLines(part, sock, sep="\r\n") } } writeLines(sprintf("--%s--", boundary), sock, sep="\r\n") } .smtp_submit_mail <- function(server, port, headers, msg, verbose=FALSE) { stopifnot(is.character(headers$From)) wait_for <- function(lcode) { done <- FALSE while (!done) { line <- readLines(con=sock, n=1) if( 0 == length(line)) stop("no data from server connection (this can be due to authentication issues)") if (verbose) message("<< ", line) code <- substring(line, 1, 3) msg <- substring(line, 5) if (code == lcode) { done <- TRUE } else { if (code >= 500 & code <= 599) stop("SMTP Error: ", msg) else message("Unknown SMTP code: ", code) } } return(list(code=code, msg=msg)) } send_command <- function(cmd, code) { if (verbose) message(">> ", cmd) writeLines(cmd, sock, sep="\r\n") wait_for(code) } nodename <- Sys.info()[4] sock <- socketConnection(host=server, port=port, blocking=TRUE) if (!isOpen(sock)) stop(sprintf("Could not connect to smtp server '%s' on port '%i'.", server, port)) on.exit(close(sock)) ## << 220 ESMTP wait_for(220) ## >> HELO localhost ## << 250 mail.statistik.uni-dortmund.de send_command(paste("HELO ", nodename), 250) ## >> MAIL FROM: ## << 250 2.1.0 Ok send_command(paste("MAIL FROM: ", headers$From), 250) ## >> RCPT TO: ## << 250 2.1.5 Ok recipients <- .get_recipients(headers) sapply(recipients, function(x) send_command(paste("RCPT TO: ", x), 250)) ## >> DATA ## << 354 blah fu send_command("DATA", 354) ## >> if (verbose) message(">> ") .write_mail(headers, msg, sock) writeLines(".", sock, sep="\r\n") wait_for(250) ## << 250 2.0.0 Ok: queued as XXXXXXXX ## >> QUIT ## << 221 2.0.0 Bye send_command("QUIT", 221) } .smtp_submit_mail_curl <- function(smtp_server, headers, curlopts = list(), msg, verbose = FALSE) { # Check if curl is installed. if (!requireNamespace("curl", quietly = TRUE)) { stop("sendmail: engine = \"curl\" needs the curl package installed. Please run: install.packages(\"curl\")", call. = FALSE) } stopifnot(is.character(headers$From)) # remove options to prevent multiple matching arguments curlopts <- setdiff(curlopts, c("smtp_server", "mail_from", "mail_rcpt", "message", "verbose")) # Default to force if (is.null(curlopts$use_ssl)) curlopts$use_ssl <- "force" from <- headers$From to <- .get_recipients(headers) # use temporary file for .write_mail sock <- file(tempfile(), open = "a+") .write_mail(headers, msg, sock) msg <- readLines(sock) # Delete temp file close(sock) unlink(sock) do.call(curl::send_mail, c(list( mail_from = from, mail_rcpt = to, message = msg, verbose = verbose, smtp_server = smtp_server), curlopts) ) } ##' Simplistic sendmail utility for R. Uses SMTP to submit a message ##' to a local SMTP server. ##' ##' @title Send mail from within R ##' ##' @param from From whom the mail message is (RFC2822 style address). ##' @param to Recipient of the message (vector of valid RFC2822 style addresses). ##' @param cc Carbon-copy recipients (vector of valid RFC2822 style addresses). ##' @param bcc Blind carbon-copy recipients (vector of valid RFC2822 style addresses). ##' @param subject Subject line of message. ##' @param msg Body text of message or a list containing ##' \code{\link{mime_part}} objects. ##' @param \dots ... ##' @param engine One of: \itemize{ ##' \item{\code{"internal"} for the internal smtp transport (default).} ##' \item{\code{"curl"} for the use of curl for transport. Enable if you need STARTTLS/SSL ##' and/or SMTP authentication. See \code{curl::\link[curl]{send_mail}}.} ##' \item{\code{"debug"} sendmail returns a RFC2822 formatted email message without sending it.} ##' } ##' @param headers Any other headers to include. ##' @param control List of SMTP server settings. Valid values are the ##' possible options for \code{\link{sendmail_options}}. ##' @param engineopts Options passed to curl if using the curl backend. \itemize{ ##' \item{For authentication pass a list with \code{username} and \code{password}.} ##' \item{\code{use_ssl} defaults to "force" if unset.} ##' \item{For available options run \code{curl::\link[curl]{curl_options}}.} ##' } ##' @seealso \code{\link{mime_part}} for a way to add attachments. ##' ##' \code{curl::\link[curl]{send_mail}} for curl SMTP URL specification. ##' @keywords utilities ##' ##' @examples ##' \dontrun{ ##' from <- sprintf("", Sys.info()[4]) ##' to <- "" ##' subject <- "Hello from R" ##' body <- list("It works!", mime_part(iris)) ##' sendmail(from, to, subject, body, ##' control=list(smtpServer="ASPMX.L.GOOGLE.COM")) ##' ##' sendmail(from="from@example.org", ##' to=c("to1@example.org", "to2@example.org"), ##' subject="SMTP auth test", ##' msg=mime_part("This message was send using sendmailR and curl."), ##' engine = "curl", ##' engineopts = list(username = "foo", password = "bar"), ##' control=list(smtpServer="smtp://smtp.gmail.com:587", verbose = TRUE) ##' ) ##' } ##' @export sendmail <- function(from, to, subject, msg, cc, bcc, ..., engine = c("internal", "curl", "debug"), headers = list(), control = list(), engineopts = list()) { ## Argument checks: stopifnot(is.list(headers), is.list(control)) if (length(from) != 1) stop("'from' must be a single address.") if (length(to) < 1) stop("'to' must contain at least one address.") # Uses the first element of vector engine <- match.arg(engine, c("internal", "curl", "debug")) get_value <- function(n, default = "") { if (n %in% names(control)) { return(control[[n]]) } else if (n %in% names(.SendmailREnv$options)) { return(.SendmailREnv$options[[n]]) } else { return(default) } } # For backward compatibility (2023-01-08 deprecated) if (get_value("transport") == "debug") engine <- "debug" headers$From <- from headers$To <- to if (!missing(cc)) headers$Cc <- cc if (!missing(bcc)) headers$Bcc <- bcc ## Encode subject if it contains none ASCII characters if (grepl("[^ -~]", subject)) { subject <- .rfc2047_subject(subject) } headers$Subject <- subject ## Add Date header if not explicitly set. This fixes the annoyance, ## that apparently Thunderbird does not sort mails correctly if they ## do not have a Date header. if (is.null(headers$Date)) headers$Date <- .rfc2822_date() verbose <- get_value("verbose", FALSE) server <- get_value("smtpServer", "localhost") if (engine == "curl") { port <- get_value("smtpPort", 587) # Add custom port to URL if none is specified using domain:port # smtps:// uses port 465 by default if (!grepl("[0-9]$", server) && !grepl("smtps:", server)) server <- paste0(server, ":", port) return( .smtp_submit_mail_curl(server, headers, curlopts = engineopts, msg, verbose = verbose)) } if (engine == "internal") { port <- get_value("smtpPort", 25) # Default transport return( .smtp_submit_mail(server, port, headers, msg, verbose)) } if (engine == "debug") { message("Recipients: ", paste(.get_recipients(headers), collapse = ", ")) # use temporary file for .write_mail sock <- file(tempfile(), open = "a+") .write_mail(headers, msg, sock) msg <- readLines(sock) # Delete temp file close(sock) unlink(sock) return(msg) } } sendmailR/R/mime_part.R0000644000176200001440000001744714356134171014513 0ustar liggesusers.mime_part_finalizer <- function(x) { if (!is.null(x$file)) file.remove(x$file) } .mime_part <- function(headers, file=NULL, text=NULL) { if (!is.null(file) && !is.null(text)) stop("Can only provide file or text for mime part.") e <- environment() reg.finalizer(e, .mime_part_finalizer, onexit=TRUE) class(e) <- "mime_part" e } .write_mime_part <- function(mp, con=stdout()) { writeLines(paste(names(mp$headers), unlist(mp$headers), sep=": "), con, sep="\r\n") writeLines("", con, sep="\r\n") if (is.null(mp$file)) writeLines(mp$text, con) else writeLines(readLines(mp$file), con, sep="\r\n") } #' @importFrom base64enc base64encode .file_attachment <- function(fn, name, type="application/octet-stream", disposition="attachment") { if (missing(name)) name <- basename(fn) text <- base64enc::base64encode(fn, linewidth=72, newline="\n") headers <- list("Content-Type"=type, "Content-Disposition"=sprintf("%s; filename=%s", disposition, name), "Content-Transfer-Encoding"="base64") .mime_part(headers=headers, text=text) } .plot_attachment <- function(plt, name=deparse(substitute(plt)), device, ...) { fn <- tempfile() device(file=fn, ...) print(plt) grDevices::dev.off() ## FIXME: Guess content type from device! res <- .file_attachment(fn, name, type="application/pdf") file.remove(fn) res } .generate_charset_convert_utf8 <- function(x) { e <- Encoding(x) # 1 If all character strings are valid utf-8 set charset utf-8 if (all(validUTF8(x))) { result <- list(x = x, charset = "; charset=utf-8") return(result) } # 2 If there is any non utf-8 encoded text, convert to utf-8 if (any(e != "unknown")) { result <- list(x = enc2utf8(x), charset = "; charset=utf-8") return(result) } # 3 Default content_type (backward compatibility) result <- list(x = x, charset = "") return(result) } ##' Create a MIME part ##' ##' @param x Object to include ##' @param name Name of mime part. Usually the filename of the ##' attachment as displayed by the e-mail client. ##' @param ... Possible further arguments for \code{mime_part} ##' implementations. ##' @return An S3 \code{mime_part} object. ##' @seealso \code{\link{mime_part.character}}, \code{\link{mime_part_html}}, ##' \code{\link{mime_part.data.frame}}, \code{\link{mime_part.matrix}}, ##' \code{\link{mime_part.ggplot}}, \code{\link{mime_part.trellis}} ##' ##' @export mime_part <- function(x, name, ...) UseMethod("mime_part", x) ##' Default MIME part method ##' ##' Creates a string representation of the object \code{x} using ##' \code{dput}. This representation is then turned into a file ##' attachment. ##' ##' @param x R object ##' @param name Filename used for attachment (sans the .R extension) ##' @param ... Ignored. ##' @return An S3 \code{mime_part} object. ##' ##' @method mime_part default ##' @export mime_part.default <- function(x, name, ...) { str <- dput(x) .mime_part(headers=list( "Content-Type"="text/plain", "Content-Disposition"=sprintf("attachment; file=%s.R", name)), text=str) } ##' Creates a MIME part from a trellis plot object ##' ##' Writes a PDF file of the plot defined by \code{x} and turns this ##' PDF file into a file attachment. ##' ##' @param x A \code{trellis} (lattice) object ##' @param name Name of attachment (sans .pdf extension). ##' @param device Graphics device used to render the plot. Defaults to ##' \code{pdf}. ##' @param ... Ignored. ##' @return An S3 \code{mime_part} object. ##' @importFrom grDevices pdf ##' @method mime_part trellis ##' @export mime_part.trellis <- function(x, name=deparse(substitute(x)), device = pdf, ...) .plot_attachment(x, name=name, device=device, ...) ##' Creates a MIME part from a ggplot2 plot object ##' ##' Writes a PDF file of the plot defined by \code{x} and turns this ##' PDF file into a file attachment. ##' ##' @param x A \code{ggplot} object ##' @param name Name of attachment (sans .pdf extension). ##' @param device Graphics device used to render the plot. Defaults to ##' \code{pdf}. ##' @param ... Ignored. ##' @return An S3 \code{mime_part} object. ##' ##' @importFrom grDevices pdf ##' @method mime_part ggplot ##' @export mime_part.ggplot <- function(x, name=deparse(substitute(x)), device = pdf, ...) .plot_attachment(x, name=name, device=device, ...) ##' Create a MIME part from a matrix. ##' ##' @param x Matrix ##' @param name Basename of file attachment that is generated. ##' @param ... Ignored. ##' @return An S3 \code{mime_part} object ##' ##' @method mime_part matrix ##' @export mime_part.matrix <- function(x, name=deparse(substitute(x)), ...) { f <- tempfile() on.exit(file.remove(f)) utils::write.table(x, file=f, ...) .file_attachment(f, name=sprintf("%s.txt", name), type="text/plain") } ##' Create a MIME part from a \code{data.frame}. ##' ##' @param x A \code{data.frame}. ##' @param name Basename of file attachment that is generated. ##' @param filename_extension Filename extension (i.e., the suffix) to be used ##' for the attached file. ##' @param ... Ignored. ##' @return An S3 \code{mime_part} object. ##' ##' @method mime_part data.frame ##' @export mime_part.data.frame <- function( x , name = deparse(substitute(x)) , filename_extension = ".txt" , ... ) { f <- tempfile() on.exit(file.remove(f)) utils::write.table(x, file = f, ...) name <- sprintf("%s%s", name, filename_extension) .file_attachment(f, name = name, type = "text/plain") } ##' Create a MIME part from a character string. If the string matches ##' a filename, a MIME part containing that file is returned instead. ##' ##' @title Create an inline character MIME Part ##' ##' @param x Character string, possibly a filename. ##' @param name Name of attachment. ##' @param type Content type of inline text. Defaults to "text/plain". ##' @param flowed Should "format=flowed" be added to the content header. ##' @param ... Ignored. ##' @return An S3 \code{mime_part} object. ##' ##' @method mime_part character ##' @export ##' @seealso \code{\link{mime_part_html}} for adding inline HTML mime_part.character <- function(x, name, type = "text/plain", flowed = FALSE, ...) { if (length(x) == 1 && file.exists(x)) { .file_attachment(x, name, ...) } else { res <- .generate_charset_convert_utf8(x) format_flowed <- ifelse(flowed, "; format=flowed", "") # e.g. Content-Type: text/plain; charset=utf-8 content_type <- paste0(type, res$charset, format_flowed) .mime_part(headers = list( "Content-Type" = content_type, "Content-Disposition" = "inline"), text = paste(res$x, collapse = "\r\n")) } } ##' Create a MIME part from a character string containing HTML. If the string matches ##' a filename the file is read and inserted as an inline character MIME part. ##' ##' @title Create an inline HTML MIME Part ##' ##' @param x Character string, vector/list of character strings ##' or path to html file. ##' @param ... Ignored. ##' @return An S3 \code{mime_part} object. ##' ##' @examples ##' \dontrun{ ##' sendmail( ##' from="from@example.org", ##' to="to1@example.org", ##' subject="inline HTML", ##' msg=mime_part_html("Hello
World"), ##' control=list(smtpServer="ASPMX.L.GOOGLE.COM") ##' ) ##' ##' sendmail( ##' from="from@example.org", ##' to="to1@example.org", ##' subject="inline HTML", ##' msg=mime_part_html("out/report.html"), ##' control=list(smtpServer="ASPMX.L.GOOGLE.COM") ##' ) ##' } ##' ##' @export mime_part_html <- function(x, ...) { if (length(x) == 1 && file.exists(x)) { x <- readLines(x) } # For compatibility with xml2::read_html() if (is.list(x)) x <- as.character(x) mime_part.character(x, type = "text/html") } sendmailR/R/options.R0000644000176200001440000000416514303154574014223 0ustar liggesusers## Option managment shamelessly taken from the lattice package. .SendmailREnv <- new.env(parent=emptyenv()) .SendmailREnv$options <- list() .update_list <- function (x, val) { if (is.null(x)) x <- list() utils::modifyList(x, val) } ##' Specify global sendmail options so that subsequent calls to ##' \code{sendmail()} do not have to set them in the \code{control} ##' argument. ##' ##' List of options: ##' \itemize{ ##' \item{smtpServer}{SMTP server to contact. This can either be the ##' mail server responsible for the destination addresses domain or a ##' smarthost provided by your ISP or institution. SMTP AUTH is ##' currently unsupported.} ##' \item{smtpPort}{SMTP port to use. Usually 25 but some institutions ##' require the use of the submission service (port 587).} ##' \item{verbose}{Show detailed information about message ##' submission. Useful for debugging.} ##' } ##' ##' @param ... Any options can be defined, using \code{name=value} or ##' by passing a list of such tagged values. However, only the ones ##' below are used in base sendmailR. ##' @return For \code{sendmail_options()}, a list of all set options ##' sorted by name. For \code{sendmail_options(name)}, a list of length ##' one containing the set value, or 'NULL' if it is unset. For uses ##' setting one or more options, a list with the previous values of ##' the options changed (returned invisibly). ##' ##' @title Set package specific options. ##' @export ##' @author Olaf Mersmann \email{olafm@@datensplitter.net} sendmail_options <- function(...) { new <- list(...) if (is.null(names(new)) && length(new) == 1 && is.list(new[[1]])) new <- new[[1]] old <- .SendmailREnv$options if (length(new) == 0) return(old) nm <- names(new) if (is.null(nm)) return(old[unlist(new)]) isNamed <- nm != "" if (any(!isNamed)) nm[!isNamed] <- unlist(new[!isNamed]) retVal <- old[nm] names(retVal) <- nm nm <- nm[isNamed] .SendmailREnv$options <- .update_list(old, new[nm]) invisible(retVal) } ##' @export ##' @rdname sendmail_options sendmailOptions <- function(...) { .Deprecated("sendmail_options") sendmail_options(...) } sendmailR/MD50000644000176200001440000000232314357751432012513 0ustar liggesusers2afd77e07245a36353c2348f4665f639 *DESCRIPTION 96a4166063208f8222c354d52719713c *NAMESPACE e2575fd1036046470b2a4d5cdcb3e960 *R/mime_part.R 46dc268584fb10718c6bf2f767b36e41 *R/options.R fcc94432164479df00b54ac896ee3f68 *R/sendmailR.r 40c6d7e6449219b84ba91dd3f8b1ec9c *README.md b7dfba5048fdd7fca999530d8e5bb69c *build/vignette.rds 35ae1eb8349ccce4cc88efc32348cc87 *inst/doc/sending-html-reports.R 53ddb626e926463f2efc8cda289c3484 *inst/doc/sending-html-reports.Rmd 2474b983c97ad256b0a7494f33534e3b *inst/doc/sending-html-reports.html 5db1fe312526a2d5e61d9eb238f9f37a *man/mime_part.Rd 447ada937faff8b9336fc9ddfea4f0c0 *man/mime_part.character.Rd c4992831ac208f140f94bbb8c61f98d2 *man/mime_part.data.frame.Rd 1ecb61142e7a2e10c0633f6c01dbc824 *man/mime_part.default.Rd 2c05c01a6b632f6529d8af56618e7445 *man/mime_part.ggplot.Rd 1729cf4f2f223455ee3f636a6cd01c46 *man/mime_part.matrix.Rd b4ce7305119225b6bde0cea55110a51c *man/mime_part.trellis.Rd a4c36670c6992a12ee6988921a773063 *man/mime_part_html.Rd 6f5f7ec4e7c0a6d1a81df2286c91cb43 *man/sendmail.Rd 3c113ac677e442c46bf61f42178adbf8 *man/sendmail_options.Rd ff2d8ba39b55fe3590b7faa4db828115 *tests/multiple_recipients.R 53ddb626e926463f2efc8cda289c3484 *vignettes/sending-html-reports.Rmd sendmailR/inst/0000755000176200001440000000000014357576575013175 5ustar liggesuserssendmailR/inst/doc/0000755000176200001440000000000014357576575013742 5ustar liggesuserssendmailR/inst/doc/sending-html-reports.html0000644000176200001440000013353614357576575020730 0ustar liggesusers Sending HTML reports inline and as attachment created with knitr

Sending HTML reports inline and as attachment created with knitr

This file shows a typical workflow for knitting .Rmd documents and sending them per E-Mail.

First we have our my_file.Rmd which looks like this:

---
title: ' '
output: 
  html_document:
    theme: null
    highlight: null
    mathjax: null
---

Hello everyone,\n

here is a calculation.

**2+2 =**

`​``{r echo=FALSE}
2+2
`​``

All the best

Render your rmarkdown file

htmlout <- tempfile(fileext = ".html")

rmarkdown::render(
      input = "my_file.Rmd",
      intermediates_dir = ".",
      output_file = htmlout,
    )

This is the resulting HTML document

Hello everyone,

here is a calculation.

2+2 =

#> [1] 4

All the best


Sending the html file per E-Mail

We can now send the the resulting html file as A) an file attachment or B) inline HTML.

A) File attachment

library(sendmailR)
sendmail(from="from@example.org",
         to="to1@example.org",
         subject="File attachment",
         msg=c(
           mime_part("Hello everyone,\n here is the newest report.\n Bye"),
           mime_part(htmlout, name = "report.html")),
         engine = "debug")
#>  [1] "From: from@example.org"                                                                                      
#>  [2] "To: to1@example.org"                                                                                         
#>  [3] "Subject: File attachment"                                                                                    
#>  [4] "Date: Wed, 11 Jan 2023 18:18:37 -0000"                                                                       
#>  [5] "MIME-Version: 1.0"                                                                                           
#>  [6] "Content-Type: multipart/mixed; boundary=\"a146a31347ec3381504dd57d7537ba235683204c1840c12174e7cfbaba9059b6\""
#>  [7] ""                                                                                                            
#>  [8] "This is a message with multiple parts in MIME format."                                                       
#>  [9] "--a146a31347ec3381504dd57d7537ba235683204c1840c12174e7cfbaba9059b6"                                          
#> [10] "Content-Type: text/plain; charset=utf-8"                                                                     
#> [11] "Content-Disposition: inline"                                                                                 
#> [12] ""                                                                                                            
#> [13] "Hello everyone,"                                                                                             
#> [14] " here is the newest report."                                                                                 
#> [15] " Bye"                                                                                                        
#> [16] "--a146a31347ec3381504dd57d7537ba235683204c1840c12174e7cfbaba9059b6"                                          
#> [17] "Content-Type: application/octet-stream"                                                                      
#> [18] "Content-Disposition: attachment; filename=report.html"                                                       
#> [19] "Content-Transfer-Encoding: base64"                                                                           
#> [20] ""                                                                                                            
#> [21] "PCFET0NUWVBFIGh0bWw+Cgo8aHRtbD4KCjxoZWFkPgoKPG1ldGEgY2hhcnNldD0idXRmLTgi"                                    
#> [22] "IC8+CjxtZXRhIG5hbWU9ImdlbmVyYXRvciIgY29udGVudD0icGFuZG9jIiAvPgo8bWV0YSBo"                                    
#> [23] "dHRwLWVxdWl2PSJYLVVBLUNvbXBhdGlibGUiIGNvbnRlbnQ9IklFPUVER0UiIC8+Cgo8bWV0"                                    
#> [24] "YSBuYW1lPSJ2aWV3cG9ydCIgY29udGVudD0id2lkdGg9ZGV2aWNlLXdpZHRoLCBpbml0aWFs"                                    
#> [25] "LXNjYWxlPTEiIC8+CgoKCjx0aXRsZT4gPC90aXRsZT4KCjxzY3JpcHQ+Ly8gUGFuZG9jIDIu"                                    
#> [26] "OSBhZGRzIGF0dHJpYnV0ZXMgb24gYm90aCBoZWFkZXIgYW5kIGRpdi4gV2UgcmVtb3ZlIHRo"                                    
#> [27] "ZSBmb3JtZXIgKHRvCi8vIGJlIGNvbXBhdGlibGUgd2l0aCB0aGUgYmVoYXZpb3Igb2YgUGFu"                                    
#> [28] "ZG9jIDwgMi44KS4KZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcignRE9NQ29udGVudExvYWRl"                                    
#> [29] "ZCcsIGZ1bmN0aW9uKGUpIHsKICB2YXIgaHMgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxs"                                    
#> [30] "KCJkaXYuc2VjdGlvbltjbGFzcyo9J2xldmVsJ10gPiA6Zmlyc3QtY2hpbGQiKTsKICB2YXIg"                                    
#> [31] "aSwgaCwgYTsKICBmb3IgKGkgPSAwOyBpIDwgaHMubGVuZ3RoOyBpKyspIHsKICAgIGggPSBo"                                    
#> [32] "c1tpXTsKICAgIGlmICghL15oWzEtNl0kL2kudGVzdChoLnRhZ05hbWUpKSBjb250aW51ZTsg"                                    
#> [33] "IC8vIGl0IHNob3VsZCBiZSBhIGhlYWRlciBoMS1oNgogICAgYSA9IGguYXR0cmlidXRlczsK"                                    
#> [34] "ICAgIHdoaWxlIChhLmxlbmd0aCA+IDApIGgucmVtb3ZlQXR0cmlidXRlKGFbMF0ubmFtZSk7"                                    
#> [35] "CiAgfQp9KTsKPC9zY3JpcHQ+Cgo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgpjb2Rle3doaXRl"                                    
#> [36] "LXNwYWNlOiBwcmUtd3JhcDt9CnNwYW4uc21hbGxjYXBze2ZvbnQtdmFyaWFudDogc21hbGwt"                                    
#> [37] "Y2Fwczt9CnNwYW4udW5kZXJsaW5le3RleHQtZGVjb3JhdGlvbjogdW5kZXJsaW5lO30KZGl2"                                    
#> [38] "LmNvbHVtbntkaXNwbGF5OiBpbmxpbmUtYmxvY2s7IHZlcnRpY2FsLWFsaWduOiB0b3A7IHdp"                                    
#> [39] "ZHRoOiA1MCU7fQpkaXYuaGFuZ2luZy1pbmRlbnR7bWFyZ2luLWxlZnQ6IDEuNWVtOyB0ZXh0"                                    
#> [40] "LWluZGVudDogLTEuNWVtO30KdWwudGFzay1saXN0e2xpc3Qtc3R5bGU6IG5vbmU7fQouZGlz"                                    
#> [41] "cGxheS5tYXRoe2Rpc3BsYXk6IGJsb2NrOyB0ZXh0LWFsaWduOiBjZW50ZXI7IG1hcmdpbjog"                                    
#> [42] "MC41cmVtIGF1dG87fQo8L3N0eWxlPgoKCgoKCgoKCgoKCjwvaGVhZD4KCjxib2R5PgoKCgoK"                                    
#> [43] "PGgxIGNsYXNzPSJ0aXRsZSB0b2MtaWdub3JlIj4gPC9oMT4KCgoKPHA+SGVsbG8gZXZlcnlv"                                    
#> [44] "bmUsPC9wPgo8cD5oZXJlIGlzIGEgY2FsY3VsYXRpb24uPC9wPgo8cD48c3Ryb25nPjIrMiA9"                                    
#> [45] "PC9zdHJvbmc+PC9wPgo8cHJlPjxjb2RlPiMmZ3Q7IFsxXSA0PC9jb2RlPjwvcHJlPgo8cD5B"                                    
#> [46] "bGwgdGhlIGJlc3Q8L3A+CgoKCjwhLS0gY29kZSBmb2xkaW5nIC0tPgoKCgo8L2JvZHk+Cjwv"                                    
#> [47] "aHRtbD4K"                                                                                                    
#> [48] "--a146a31347ec3381504dd57d7537ba235683204c1840c12174e7cfbaba9059b6--"

B) Inline HTML

sendmail(from="from@example.org",
       to="to1@example.org",
       subject="Inline HTML",
       msg=mime_part_html(htmlout),
       engine = "debug")
#> Recipients: to1@example.org
#>  [1] "From: from@example.org"                                                                                      
#>  [2] "To: to1@example.org"                                                                                         
#>  [3] "Subject: Inline HTML"                                                                                        
#>  [4] "Date: Wed, 11 Jan 2023 18:18:37 -0000"                                                                       
#>  [5] "MIME-Version: 1.0"                                                                                           
#>  [6] "Content-Type: multipart/mixed; boundary=\"e0938c30b586dd1b560656ddedf55a372d9f0338445bda5cc6f7bfdce110e607\""
#>  [7] ""                                                                                                            
#>  [8] "This is a message with multiple parts in MIME format."                                                       
#>  [9] "--e0938c30b586dd1b560656ddedf55a372d9f0338445bda5cc6f7bfdce110e607"                                          
#> [10] "Content-Type: text/html; charset=utf-8"                                                                      
#> [11] "Content-Disposition: inline"                                                                                 
#> [12] ""                                                                                                            
#> [13] "<!DOCTYPE html>"                                                                                             
#> [14] ""                                                                                                            
#> [15] "<html>"                                                                                                      
#> [16] ""                                                                                                            
#> [17] "<head>"                                                                                                      
#> [18] ""                                                                                                            
#> [19] "<meta charset=\"utf-8\" />"                                                                                  
#> [20] "<meta name=\"generator\" content=\"pandoc\" />"                                                              
#> [21] "<meta http-equiv=\"X-UA-Compatible\" content=\"IE=EDGE\" />"                                                 
#> [22] ""                                                                                                            
#> [23] "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />"                                  
#> [24] ""                                                                                                            
#> [25] ""                                                                                                            
#> [26] ""                                                                                                            
#> [27] "<title> </title>"                                                                                            
#> [28] ""                                                                                                            
#> [29] "<script>// Pandoc 2.9 adds attributes on both header and div. We remove the former (to"                      
#> [30] "// be compatible with the behavior of Pandoc < 2.8)."                                                        
#> [31] "document.addEventListener('DOMContentLoaded', function(e) {"                                                 
#> [32] "  var hs = document.querySelectorAll(\"div.section[class*='level'] > :first-child\");"                       
#> [33] "  var i, h, a;"                                                                                              
#> [34] "  for (i = 0; i < hs.length; i++) {"                                                                         
#> [35] "    h = hs[i];"                                                                                              
#> [36] "    if (!/^h[1-6]$/i.test(h.tagName)) continue;  // it should be a header h1-h6"                             
#> [37] "    a = h.attributes;"                                                                                       
#> [38] "    while (a.length > 0) h.removeAttribute(a[0].name);"                                                      
#> [39] "  }"                                                                                                         
#> [40] "});"                                                                                                         
#> [41] "</script>"                                                                                                   
#> [42] ""                                                                                                            
#> [43] "<style type=\"text/css\">"                                                                                   
#> [44] "code{white-space: pre-wrap;}"                                                                                
#> [45] "span.smallcaps{font-variant: small-caps;}"                                                                   
#> [46] "span.underline{text-decoration: underline;}"                                                                 
#> [47] "div.column{display: inline-block; vertical-align: top; width: 50%;}"                                         
#> [48] "div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}"                                                
#> [49] "ul.task-list{list-style: none;}"                                                                             
#> [50] ".display.math{display: block; text-align: center; margin: 0.5rem auto;}"                                     
#> [51] "</style>"                                                                                                    
#> [52] ""                                                                                                            
#> [53] ""                                                                                                            
#> [54] ""                                                                                                            
#> [55] ""                                                                                                            
#> [56] ""                                                                                                            
#> [57] ""                                                                                                            
#> [58] ""                                                                                                            
#> [59] ""                                                                                                            
#> [60] ""                                                                                                            
#> [61] ""                                                                                                            
#> [62] ""                                                                                                            
#> [63] "</head>"                                                                                                     
#> [64] ""                                                                                                            
#> [65] "<body>"                                                                                                      
#> [66] ""                                                                                                            
#> [67] ""                                                                                                            
#> [68] ""                                                                                                            
#> [69] ""                                                                                                            
#> [70] "<h1 class=\"title toc-ignore\"> </h1>"                                                                       
#> [71] ""                                                                                                            
#> [72] ""                                                                                                            
#> [73] ""                                                                                                            
#> [74] "<p>Hello everyone,</p>"                                                                                      
#> [75] "<p>here is a calculation.</p>"                                                                               
#> [76] "<p><strong>2+2 =</strong></p>"                                                                               
#> [77] "<pre><code>#&gt; [1] 4</code></pre>"                                                                         
#> [78] "<p>All the best</p>"                                                                                         
#> [79] ""                                                                                                            
#> [80] ""                                                                                                            
#> [81] ""                                                                                                            
#> [82] "<!-- code folding -->"                                                                                       
#> [83] ""                                                                                                            
#> [84] ""                                                                                                            
#> [85] ""                                                                                                            
#> [86] "</body>"                                                                                                     
#> [87] "</html>"                                                                                                     
#> [88] "--e0938c30b586dd1b560656ddedf55a372d9f0338445bda5cc6f7bfdce110e607--"
sendmailR/inst/doc/sending-html-reports.Rmd0000644000176200001440000000445314357517542020466 0ustar liggesusers--- title: "Sending HTML reports inline and as attachment created with knitr" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Sending HTML reports inline and as attachment created with knitr} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r echo = FALSE} knitr::opts_chunk$set(collapse = TRUE, comment = "#>", fig.width = 7, fig.height = 5, warning = FALSE, message = FALSE) if (!requireNamespace("rmarkdown", quietly = TRUE) || !requireNamespace("htmltools", quietly = TRUE)) { knitr::opts_chunk$set(eval = FALSE, tidy = FALSE) } ``` This file shows a typical workflow for knitting *.Rmd* documents and sending them per E-Mail. First we have our **my_file.Rmd** which looks like this: ````{=html}
---
title: ' '
output: 
  html_document:
    theme: null
    highlight: null
    mathjax: null
---

Hello everyone,\n

here is a calculation.

**2+2 =**

`​``{r echo=FALSE}
2+2
`​``

All the best
```` ```{r include=FALSE} test.Rmd <- "--- title: ' ' output: html_document: theme: null highlight: null mathjax: null --- Hello everyone,\n here is a calculation. **2+2 =** \```{r echo=FALSE} 2+2 \``` All the best " writeLines(test.Rmd, con = "my_file.Rmd") ``` ## Render your rmarkdown file ```{r echo=TRUE, results = 'hide'} htmlout <- tempfile(fileext = ".html") rmarkdown::render( input = "my_file.Rmd", intermediates_dir = ".", output_file = htmlout, ) ``` ## This is the resulting HTML document ```{r echo=FALSE, results='asis'} unlink("my_file.Rmd") htmltools::includeHTML(htmlout) ``` ------------------------------------------------------------------------ ## Sending the html file per E-Mail We can now send the the resulting html file as A) an file attachment or B) inline HTML. ### A) File attachment ```{r} library(sendmailR) sendmail(from="from@example.org", to="to1@example.org", subject="File attachment", msg=c( mime_part("Hello everyone,\n here is the newest report.\n Bye"), mime_part(htmlout, name = "report.html")), engine = "debug") ``` ### B) Inline HTML ```{r message=TRUE} sendmail(from="from@example.org", to="to1@example.org", subject="Inline HTML", msg=mime_part_html(htmlout), engine = "debug") ``` sendmailR/inst/doc/sending-html-reports.R0000644000176200001440000000323014357576575020150 0ustar liggesusers## ----echo = FALSE------------------------------------------------------------- knitr::opts_chunk$set(collapse = TRUE, comment = "#>", fig.width = 7, fig.height = 5, warning = FALSE, message = FALSE) if (!requireNamespace("rmarkdown", quietly = TRUE) || !requireNamespace("htmltools", quietly = TRUE)) { knitr::opts_chunk$set(eval = FALSE, tidy = FALSE) } ## ----include=FALSE------------------------------------------------------------ test.Rmd <- "--- title: ' ' output: html_document: theme: null highlight: null mathjax: null --- Hello everyone,\n here is a calculation. **2+2 =** \```{r echo=FALSE} 2+2 \``` All the best " writeLines(test.Rmd, con = "my_file.Rmd") ## ----echo=TRUE, results = 'hide'---------------------------------------------- htmlout <- tempfile(fileext = ".html") rmarkdown::render( input = "my_file.Rmd", intermediates_dir = ".", output_file = htmlout, ) ## ----echo=FALSE, results='asis'----------------------------------------------- unlink("my_file.Rmd") htmltools::includeHTML(htmlout) ## ----------------------------------------------------------------------------- library(sendmailR) sendmail(from="from@example.org", to="to1@example.org", subject="File attachment", msg=c( mime_part("Hello everyone,\n here is the newest report.\n Bye"), mime_part(htmlout, name = "report.html")), engine = "debug") ## ----message=TRUE------------------------------------------------------------- sendmail(from="from@example.org", to="to1@example.org", subject="Inline HTML", msg=mime_part_html(htmlout), engine = "debug")