Is it possible to cc recipients using sendmail in R? - r

I want to send a single mail to multiple recipients from R. I am able to achieve this using sendmail function but when recipients recieve the email, they see only their email address in to field. Looks like sendmail internally loops and sends individual emails to each recipient which is not a true carbon copy. It is important that each recipient sees all the recipients intended for their specific email (business requirement, because they need to reply to all recipients of this email). how can I achieve this using R?
my code
require(sendmailR)
to <- c("vasudeva.naik#abc.com")
header <- list(cc=c("alok.jadhav#abc.com"))
x <- sendmail("toto#abc.com", to, "test", "testing", header=header,control=list(smtpServer=server,verbose=TRUE))
<< 220 equity.xyz.com ESMTP Sendmail 8.11.7p1+Sun/8.11.7; Thu, 11 Jul 2013 21:31:43 -0400 (EDT)
>> HELO HKD03836654
<< 250 equity.xyz.com Hello HKD03836654.gbl.ad.net [169.34.175.142], pleased to meet you
>> MAIL FROM: toto#abc.com
<< 250 2.1.0 toto#abc.com... Sender ok
>> RCPT TO: vasudeva.naik#abc.com
<< 250 2.1.5 vasudeva.naik#abc.com... Recipient ok
>> DATA
<< 354 Enter mail, end with "." on a line by itself
>> <message data>
<< 250 2.0.0 r6C1Vh101169 Message accepted for delivery
>> QUIT
<< 221 2.0.0 equity.csfb.com closing connection
Output from debug option. header information is not present in the debug output.
> sendmail("toto#abc.com", to, "test", "testing", header=header,control=list(smtpServer=server,transport="debug"))
From: toto#abc.com
To: vasudeva.naik#abc.com
Subject: test
Date: Mon, 15 Jul 2013 02:15:29 -0000
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="1a556aa6576e231876dabb67e5a4f58730d3a228654e14705503b6985a6a6707"
This is a message with multiple parts in MIME format.
--1a556aa6576e231876dabb67e5a4f58730d3a228654e14705503b6985a6a6707
Content-Type: text/plain; format=flowed
testing
--1a556aa6576e231876dabb67e5a4f58730d3a228654e14705503b6985a6a6707--
Thanks.

The problem is caused by the usage of parameter header instead of headers. However, it is not that stupid typo as one might think. As we know, we can abbreviate parameter names when calling functions:
myfun <- function(xx = 1) print(xx)
myfun(x = 2)
# [1] 2
It is also possible when having ...:
myfun <- function(xx = 1, ...) print(xx)
myfun(x = 2)
[1] 2
But in this case we have a different and uncommon order of parameters:
sendmail(from, to, subject, msg, ..., headers = list(), control = list())
which not surprisingly cause such problems:
myfun <- function(..., yy = 1) print(yy)
myfun(y = 2)
[1] 1

You need to combine all the real recipients and send the email to each one of the them separately. CC is just informational as such; leave it out and you get BCC So, for example:
to <- c("vasudeva.naik#abc.com") # addresses for the "To" header
cc <- c("alok.jadhav#abc.com") # addresses for the "CC" header
bcc <- c("...") # more addresses, but these won't be visible anywhere
recipients <- c(to, cc, bcc) # need to send the email to everyone (FIXME: drop duplicates)
header <- list(cc=cc) # let everyone know who else gets the mail
x <- sendmail("toto#abc.com", recipients, "test", "testing", header=header, control=list(smtpServer=server,verbose=TRUE))
If you want all addresses in the To header you could use header <- list(to=to) instead.
Note though, above is untested. Should work in theory, but sendmailR might have other plans wrt handling some of the arguments.
To elaborate on my earlier comment. There are two parts to sending email, SMTP that's the protocol for delivering the message to the recipients, and the message content itself.
SMTP that handles the delivery looks something like:
MAIL FROM: toto#abc.com
RCPT TO: vasudeva.naik#abc.com
DATA
<message content here, see below>
.
Note that the FROM and TO here match the arguments to the sendmail() function. That determines who receives the mail.
Now, the message content (well, just the headers) looks something like this:
From: no-reply#example.com
To: everyone#example.com
CC: everyone-else#example.com
And yes the From and To are completely different from the previous ones. This is what the recipients get and see, but it bears no relevance to who actually gets the email. That's why spam in your inbox appears as something you've sent to someone else, even though you're the actual recipient.

Try:
> for (to in recipients) {
+ sendmail(from, to, subject, msg, control...

A couple of possibilities (untested):
Put the list of recipients as the first line in your message body. Rather clunky, but it works. I've actually seen this done with a Bcc: field (which defeats the point of Bcc:, but never mind that).
Instead of a vector of mail recipients, have your to argument be a single string containing all the recipients, separated by commas.

I have faced this problem before, would love to know a more direct solution, but the way I solved it was to create a distribution list and send a single mail to the distribution list. That way everyone sees and can reply all to the list. Hope this solves your problem.

Related

Using HTTR POST to Create a Azure Devops Work Item

Im attempting to setup some R code to create a new work item task in Azure Devops. Im okay with a mostly empty work item to start with if thats okay to do (my example code is only trying to create a work item with a title).
I receive a 203 response but the work item doesn't appear in Devops.
Ive been following this documentation from Microsoft, I suspect that I might be formatting the body incorrectly.
https://learn.microsoft.com/en-us/rest/api/azure/devops/wit/work%20items/create?view=azure-devops-rest-5.1
Ive tried updating different fields and formatting the body differently with no success. I have attempted to create either a bug or feature work item but both return the same 203 response.
To validate that my token is working I can GET work item data by ID but the POST continues to return a 203.
require(httr)
require(jsonlite)
url <- 'https://dev.azure.com/{organization}/{project}/_apis/wit/workitems/$bug?api-version=5.1'
headers = c(
'Authorization' = sprintf('basic %s',token),
'Content-Type' = 'application/json-patch+json',
'Host' = 'dev.azure.com'
)
data <- toJSON(list('body'= list("op"= "add",
"path"= "/fields/System.AreaPath",
"value"= "Sample task")), auto_unbox = TRUE, pretty = TRUE)
res <- httr::POST(url,
httr::add_headers(.headers=headers),
httr::verbose(),
body = data)
Im expecting a 200 response (similar to the example in the link above) and a work item task in Azure DevOps Services when I navigate to the website.
Im not the best with R so please be detailed. Thank you in advanced!
The POST continues to return a 203.
The HTTP response code 203 means Non-Authoritative Information, it should caused by your token format is converted incorrectly.
If you wish to provide the personal access token through an HTTP
header, you must first convert it to a Base64 string.
Refer to this doc described, if you want to use VSTS rest api, you must convert your token to a Base64 string. But in your script, you did not have this script to achieve this convert.
So, please try with the follow script to convert the token to make the key conformant with the requirements(load the base64enc package first):
require(base64enc)
key <- token
keys <- charToRaw(paste0(key,":token"))
auth <- paste0("Basic ",base64encode(keys))
Hope this help you get 200 response code
I know this question is fairly old, but I cannot seem to find a good solution posted yet. So, I will add my solution in case others find themselves in this situation. Note, this did take some reading through other SO posts and trial-and-error.
Mengdi is correct that you do need to convert your token to a Base64 string.
Additionally, Daniel from this SO question pointed out that:
In my experience with doing this via other similar mechanisms, you have to include a leading colon on the PAT, before base64 encoding.
Mengdi came up big in another SO solution
Please try with adding [{ }] outside your request body.
From there, I just made slight modifications to your headers and data objects. Removed 'body' from your json, and made use of paste to add square brackets as well. I found that the Rcurl package made base64 encoding a breeze. Then I was able to successfully create a blank ticket (just titled) using the API! Hope this helps someone!
library(httr)
library(jsonlite)
library(RCurl)
#user and PAT for api
userid <- ''
token= 'whateveryourtokenis'
url <- 'https://dev.azure.com/{organization}/{project}/_apis/wit/workitems/$bug?api-version=5.1'
#create a combined user/pat
#user id can actually be a blank string
#RCurl's base64 seemed to work well
c_id <- RCurl::base64(txt = paste0(userid,
":",
devops_pat
),
mode = "character"
)
#headers for api call
headers <- c(
"Authorization" = paste("Basic",
c_id,
sep = " "
),
'Content-Type' = 'application/json-patch+json',
'Host' = 'dev.azure.com'
)
#body
data <- paste0("[",
toJSON(list( "op"= "add",
"path"= "/fields/System.Title",
"value"= "API test - please ignore"),
auto_unbox = TRUE,
pretty = TRUE
),
"]"
)
#make the call
res <- httr::POST(url,
httr::add_headers(.headers=headers),
httr::verbose(),
body = data
)
#check status
status <- res$status_code
#check content of response
check <- content(res)

How can I programatically obtain the content size of a web page using R

I am looking to scrape the web pages of several golfers on wikipedia. Some of the player names are identical to other people and, in that case, the URL has to have the text '(golfer)' appended to reach the right page
I am looking to try every player with this addition and if the page does not exist then revert to the plain name
There may be a better approach, but I had hoped that I could obtain the content size of the response. If it did not reach a certain level e.g. 2kb then that was not a valid page
library(httr)
base_url <- "https://en.wikipedia.org/w/api.php"
query_params <- list(action = "parse",
page = "Patrick Reed_(golfer)",
format = "xml")
resp <- GET(url = base_url, query = query_params)
resp
Response [https://en.wikipedia.org/w/api.php?
action=parse&page=Patrick%20Reed_%28golfer%29&format=xml]
Date: 2018-04-08 08:35
Status: 200
Content-Type: text/xml; charset=utf-8
Size: 402 B
So a suitably low size gets reported but I am not sure how to get to it when I expand the list, resp. According to httr quickstart there is something in the headers referencing content-length but I am unable to discover it
TIA

Need help decoding the results of scapy.sr1 for both IPv4 and IPv6

I have the following code:
ans4 = sr1(IP(dst=hostname) / ICMP())
ans6 = sr1(IPv6(dst=hostname) / ICMPv6EchRequest())
I am trying to parse the contents of ans4 and ans6. In particular, I’d like to know if hostname actually responded with a ping reply. I see ans4.show() and ans6.show() and ans6.summary() and ans6.summary() and a bunch of other methods and attributes, but I can’t seem to find what I am looking for. I can parse repr(ans), which is a string, but is that the best way to do it?
The question is a bit vaguely asked, but if I got you right - this should do the job:
>>> hostname = 'www.google.com'
>>> ans,unans=sr(IP(dst=hostname)/ICMP())
Begin emission:
.......Finished to send 1 packets.
..*
Received 10 packets, got 1 answers, remaining 0 packets
>>> ans.summary( lambda(s,r): r.sprintf("%IP.src% : %ICMP.type%") )
216.58.208.100 : echo-reply

NodeMCU http.get() and UTF-8 charset

I am using the http module of the NodeMCU dev branch to make a GET request to the Google Calendar API. However, when I retrieve the events and parse answer, I get strange chars due to a non-proper encoding.
I tried to add Accept-Charset: utf-8 in the header of the request, but the request fails (code=-1).
Is there a way to set the charset, or convert it afterwards in lua?
function bdayshttps(curr_date)
if (string.len(curr_date) == 10) then
http.get("https://www.googleapis.com/calendar/v3/calendars/"..
"<CalendarID>/events"..
"?timeMax="..curr_date.."T23%3A59%3A59-00%3A00"..
"&timeMin="..curr_date.."T00%3A00%3A00-00%3A00&fields=items%2Fsummary"..
"&key=<Google Calendar API key>", "Accept-Charset: utf-8", function(code, data)
if (code < 0) then
print("msg:birthdays error")
else
if (code == 200) then
output = ""
for line in data:gmatch"\"summary\": \"[^\n]*" do
output = output..line:sub(13, line:len()-1)..";"
end
print("bday:"..output)
end
end
end)
end
end
For obvious reasons, I erased the calendarID and API key.
EDIT:
The result of this code returns msg:birthday error, meaning the GET request returns a code=-1.
When replacing the "Accept-Charset: utf-8" by nil in the header, I get:
Loïc Simonetti instead of Loïc Simonetti.
The API docs say that you need to append \r\n to every header you set. There's an example in the docs for http.post().
Hence, instead of "Accept-Charset: utf-8" you should set "Accept-Charset: utf-8\r\n".
For the second part of your question (now that the response is working), it appears you are receiving back valid UTF8 Unicode.
Loïc corresponds to the following UTF8 code units: 4C 6F C3 AF 63
Loïc has the following byte values in a common encoding (CodePage 1252): 4C 6F C3 AF 63.
So my guess is the terminal or other device you're using to view the bytes is mangling things as opposed to your request/response being incorrect. Per #Marcel's link above too, Lua does not handle Unicode at all so this is about the best you can do (safely receive, store, and then send it back later)

Get data via Netatmo API within R

I tried to get data from a netatmo station I have access to via API. The following code I used in R.
myapp <- oauth_app("my_netatmo",key="my_netatmo_client_id",secret="my_netatmo_client_secret")
ep <- oauth_endpoint(authorize = "http://api.netatmo.net/oauth2/authorize",access = "http://api.netatmo.net/oauth2/token")
sig_tok <- oauth2.0_token(ep,myapp, scope="read_station")
#after that I get redirected to my browser to log in and after that sig_tok contains an access token
sig <- config(token = sig_tok)
html_get<-GET("http://api.netatmo.net/api/devicelist",sig)
html_get contains this:
html_get
Response [http://api.netatmo.net/api/devicelist]
Status: 400
Content-type: application/json; charset=utf-8
{"error":{"code":1,"message":"Access token is missing"}}
What am I doing wrong since "sig" seems to contain a token:
sig$token$credentials$access_token
[1] "5**********************f|3**********************a"
There are two tokens or am I wrong (because of "|" in between)?
The '|' inside the access_token is part of it, it is only one access token.
From the documentation: http://dev.netatmo.com/doc/methods/devicelist,
the parameter name is: "access_token". I don't know the R language, but it seems you are sending "token" as a parameter, and not "access_token". It may explain the issue.

Resources