Parse email fields with Golang - email

I am trying to parse my emails in Go and I need help.
How to get access to Content-type field of mail?
cmd, _ = c.Fetch(set, "BODY[HEADER]", "BODY[1]")
for cmd.InProgress() {
for _, rsp = range cmd.Data {
header := imap.AsBytes(rsp.MessageInfo().Attrs["BODY[HEADER]"])
body := imap.AsString(rsp.MessageInfo().Attrs["BODY[1]"])
if msg, _ := mail.ReadMessage(bytes.NewReader(header)); msg != nil {
with this I can gain access to Body and Header, but when email contain included file then with BODY[1] I have all meta-data, not only pure text. To avoid that I can use BODY[1.1], but I need condition by Content-Type:[multipart/alternative] and I can't gain access ot that field.

Ok, so i figured it out by my self. But anyway, maybe someone else interested in that. You can have access to varios fields of mail by
msg.Header.Get("Content-type")
and instead of Content-type you can put any header part name.
fmt.println(msg)
to know what name fields it have

Related

TypeError: send_mail() missing 3 required positional arguments: 'message', 'from_email', and 'recipient_list'

so I'm wanting to make this form where the client fills their name, email and a message. Then that message and their name is sent to my mail address and another mail is sent from my address to the clients one telling that their mail was sent successfully.
I already did this on another project and literally just copied changing the name of the functions n stuff but it doesn't work.
views.py
def send_email(email):
context = {'email': email}
template = get_template('emails/message-confirmation.html')
content = template.render(context)
email = EmailMultiAlternatives(
'Test email',
'AmiSalta message confirmation',
settings.EMAIL_HOST_USER,
[email]
)
email.attach_alternative(content, 'text/html')
email.send()
def function(request):
form = ContactForm_es()
if request.method == 'POST':
email = request.POST.get('email')
send_mail(email)
form = ContactForm_es(request.POST)
if form.is_valid():
email = form.cleaned_data['email']
full_name = form.cleaned_data['full_name']
body = form.cleaned_data['body']
send_mail(full_name,body,email, ['******#gmail.com'])
return render(request, 'es/home.html', {
'form': form,
})
I'm going crazy bc is the last thing I need to do and I already did once but I just can't make it work. Please if someone knows what's wrong let me know, thanks in advance.
I was getting the same issue you are having and the thing I was doing wrong was in the URLs.py file I was calling send_mail directly instead of the veiw_func that sends the mail that is why it was saying all the three required parameters are missing.
check your URLs.py file you might be having the same issue
Check if you use your send_email in urls.py instead of send_mail. The name of your function is very similar to the django's send_mail() function. You can easily confuse yourself.
Change the name of function def send_email(email): to something def mailtest(email):
you are getting thise error beacause
you are trying to overwrite the function

Delphi 10.1: How to get JSON string stored in the body parameter of a REST request (TCustomRESTRequest.Body)?

I'm implementing a REST client application which communicates with the Coinbase GDAX Trading API in the JSON format (www.coinbase.com and https://docs.gdax.com/#introduction). I'm facing a problem in signing REST request messages with POST. Signing REST request messages with GET is working fine. Mainly because GET messages don't have a body parameter, which would be part of the signature when available. And this body parameter drives me crazy :-) I'm struggling to get the JSON string stored in the body parameter of a REST request (TCustomRESTRequest.Body). I need this JSON string to sign the REST request message properly. If I pass the body JSON string outside of TCustomRESTRequest.Body (ugly workaround), I get HTTP error 400 (bad request) with additional information "invalid signature". I assume the JSON string in TCustomRESTRequest.Body is somehow altered from the original JSON string. What I would like to achieve is to read out the JSON string directly from TCustomRESTRequest.Body, and then do the signing.
All the authentication and signing I'm doing in my class TCoinbaseAuthenticator (which is inherited from TCustomAuthenticator), or more specific in the DoAuthenticate method:
procedure TCoinbaseAuthenticator.DoAuthenticate(ARequest: TCustomRESTRequest);
var
DateTimeUnix: Int64;
DateTimeUnixStr: string;
Sign: string;
HttpMethod: string;
BodyStr: string;
begin
inherited;
ARequest.Params.BeginUpdate;
try
DateTimeUnix := DateTimeToUnix(TTimeZone.Local.ToUniversalTime(Now));
DateTimeUnixStr := IntToStr(DateTimeUnix);
HttpMethod := HttpMethodToString(ARequest.Method);
// BodyStr := ARequest.Body ... << here I'm strugging to get the JSON string
Sign := GenerateSignature(DateTimeUnixStr, HttpMethod, '/' + ARequest.Resource, BodyStr);
ARequest.AddAuthParameter('CB-ACCESS-KEY', FAPIKey, TRESTRequestParameterKind.pkHTTPHEADER, [TRESTRequestParameterOption.poDoNotEncode]);
ARequest.AddAuthParameter('CB-ACCESS-SIGN', Sign, TRESTRequestParameterKind.pkHTTPHEADER, [TRESTRequestParameterOption.poDoNotEncode]);
ARequest.AddAuthParameter('CB-ACCESS-TIMESTAMP', DateTimeUnixStr, TRESTRequestParameterKind.pkHTTPHEADER, [TRESTRequestParameterOption.poDoNotEncode]);
ARequest.AddAuthParameter('CB-ACCESS-PASSPHRASE', FAPIPassphrase, TRESTRequestParameterKind.pkHTTPHEADER, [TRESTRequestParameterOption.poDoNotEncode]);
ARequest.AddAuthParameter('CB-VERSION', '2015-07-22', TRESTRequestParameterKind.pkHTTPHEADER, [TRESTRequestParameterOption.poDoNotEncode]);
ARequest.AddAuthParameter('Content-Type', 'application/json', TRESTRequestParameterKind.pkHTTPHEADER, [TRESTRequestParameterOption.poDoNotEncode]);
finally
ARequest.Params.EndUpdate;
end;
end;
Here is my signature generating function (I think the code is ok, because it works fine if I don't have to consider the body parameter, e.g. for GET requests):
function TCoinbaseAuthenticator.GenerateSignature(ATimeStamp: string; AMethod: string; AURL: string; ABody: string): string;
var
s: string;
SignStr: string;
BitDigest: T256BitDigest;
key: string;
begin
s := ATimeStamp+AMethod+AURL+ABody;
key := MimeDecodeString(FAPISecret);
BitDigest := CalcHMAC_SHA256(key, s);
SignStr := SHA256DigestAsString(BitDigest);
SignStr := MimeEncodeStringNoCRLF(SignStr);
Result := SignStr;
end;
Some more insights of the Coinbase (GDAX) message signing process:
All REST requests must contain the following headers:
CB-ACCESS-KEY: The api key as a string (created by Coinbase)
CB-ACCESS-SIGN: The base64-encoded signature
CB-ACCESS-TIMESTAMP: A timestamp for your request
CB-ACCESS-PASSPHRASE: The passphrase you specified when creating the API key
The CB-ACCESS-SIGN header is generated by creating a sha256 HMAC using the base64-decoded secret key on the prehash string timestamp + method (GET,POST, etc.) + requestPath + body (where + represents string concatenation) and base64-encode the output. The timestamp value is the same as the CB-ACCESS-TIMESTAMP header.
The body is the request body string or omitted if there is no request body (typically for GET requests).
Thanks a lot for any help!
Thanks a lot for your comment, Remy! I did indeed use the wrong charset for the signature calculation. So at least my super ugly workaround (passing the body JSON string outside of TCustomRESTRequest.Body into the authenticator class) is working.
For the first part of the problem I don't think there is an easy solution. I got some support from Embarcadero which I would like to share with others who have a similar problem.
Looking at the TBody class, which is used for the Body property, this looks like it only has properties to write to - there isn't anything that will help in reading it back. I found that if I added a body to a TRequest, this created a TRestRequestParameter with a name of body. I would therefore suggest that you can get to it via RestRequest1.Params.ParameterByName('body');
Unfortunately this proposal is not working. Reason:
The parameter "body" is stored in the body request parameter list (TCustomRESTRequest.FBody.FParams), and not in RESTRequest parameter list (TCustomRESTRequest.Params). Since TCustomRESTRequest.FBody.FParams doesn't have a public property, I cannot access the field from outside. Later the parameters are copied from TCustomRESTRequest.FBody.FParams to TCustomRESTRequest.Params, but this is too late in my case, because the authenticator (where I calculate the signature) is called earlier. Meaning in my TCoinbaseAuthenticator.DoAuthenticate(ARequest: TCustomRESTRequest) method the parameter list in ARequest is still empty.

URL Builder/Query builder in Go

I am interested in dynamically taking arguments from the user as input through a browser or a CLI to pass in those parameters to the REST API call and hence construct the URL dynamically using Go which is going to ultimately fetch me some JSON data.
I want to know some techniques in Go which could help me do that. One ideal way I thought was to use a map and populate it with arguments keys and corresponding values and iterate over it and append it to the URL string. But when it comes to dynamically taking the arguments and populating the map, I am not very sure how to do that in Go. Can someone help me out with some code snippet in Go?
Request example:
http://<IP>:port?api=fetchJsonData&arg1=val1&arg2=val2&arg3=val3.....&argn=valn
There's already url.URL that handles that kind of things for you.
For http handlers (incoming requests) it's a part of http.Request (access it with req.URL.Query()).
A very good example from the official docs:
u, err := url.Parse("http://bing.com/search?q=dotnet")
if err != nil {
log.Fatal(err)
}
u.Scheme = "https"
u.Host = "google.com"
q := u.Query()
q.Set("q", "golang")
u.RawQuery = q.Encode()
fmt.Println(u)
https://github.com/golang/go/issues/17340#issuecomment-251537687
https://play.golang.org/p/XUctl_odTSb
package main
import (
"fmt"
"net/url"
)
func someURL() string {
url := url.URL{
Scheme: "https",
Host: "example.com",
}
return url.String()
}
func main() {
fmt.Println(someURL())
}
returns:
https://example.com
url.Values{} provides an interface for building query params. You can construct inline and/or use .Add for dynamic properties:
queryParams := url.Values{
"checkin": {request.CheckIn},
"checkout": {request.CheckOut},
}
if request.ReservationId {
queryParams.Add("reservationId", request.ReservationId)
}
url := "https://api.example?" + queryParams.Encode() // checkin=...&checkout=...

setting up script to include google docs form data in email notification

I've setup a form using googledocs. I just want to have the actual data entered into the form emailed to me, as opposed to the generic response advising that the form has been completed.
I have no skill or experience with code etc, but was sure i could get this sorted. I've spent hours+hours and haven't had any luck.
My form is really basic.it has 5 fields. 4 of which are just text responses, and one multiple choice.
I found this tute online (http://www.labnol.org/internet/google-docs-email-form/20884/) which i think sums up what i'm trying to do, but have not been able to get it to work.
from this site i entered the following code:
function sendFormByEmail(e)
{
var email = "reports.mckeir#gmail.com";
var subject = "Google Docs Form Submitted";
var s = SpreadsheetApp.getActiveSheet();
var headers = s.getRange(1,1,1,s.getLastColumn()).getValues()[0];
var message = "";
for(var i in headers)
message += headers[i] + ' = '+ e.namedValues[headers[i]].toString() + "\n\n";
MailApp.sendEmail(email, subject, message);
}
To this, i get the following response: ->
Your script, Contact Us Form Mailer, has recently failed to finish successfully. A summary of the failure(s) is shown below. To configure the triggers for this script, or change your setting for receiving future failure notifications, click here.
The script is used by the document 100% Club.
Details:
Start Function Error Message Trigger End
12/3/12 11:06 PM sendFormByEmail TypeError: Cannot call method "toString" of undefined. (line 12) formSubmit 12/3/12 11:06 PM
Is anyone able to help shed some light on this for me? I'm guessing i'm not including some data neeeded, but i honestly have no clue.
Workaround http://www.labnol.org/internet/google-docs-email-form/20884/
You have to setup app script to forward the data as email.
I'll point to the comment above that solved it for me: https://stackoverflow.com/a/14576983/134335
I took that post a step further:
I removed the normal notification. The app script makes that generic text redundant and useless now
I modified the script to actually parse the results and build the response accordingly.
function sendFormByEmail(e)
{
var toEmail = "changeme";
var name = "";
var email = "";
// Optional but change the following variable
// to have a custom subject for Google Docs emails
var subject = "Google Docs Form Submitted";
var message = "";
// The variable e holds all the form values in an array.
// Loop through the array and append values to the body.
var s = SpreadsheetApp.getActiveSheet();
var headers = s.getRange(1,1,1,s.getLastColumn()).getValues()[0];
// Credit to Henrique Abreu for fixing the sort order
for(var i in headers) {
if (headers[i] = "Name") {
name = e.namedValues[headers[i]].toString();
}
if (headers[i] = "Email") {
email = e.namedValues[headers[i]].toString();
}
if (headers[i] = "Subject") {
subject = e.namedValues[headers[i]].toString();
}
if (headers[i] = "Message") {
message = e.namedValues[headers[i]].toString();
}
}
// See https://developers.google.com/apps-script/reference/mail/mail-app#sendEmail(String,String,String,Object)
var mailOptions = {
name: name,
replyTo: email,
};
// This is the MailApp service of Google Apps Script
// that sends the email. You can also use GmailApp here.
MailApp.sendEmail(toEmail, subject, message, mailOptions);
// Watch the following video for details
// http://youtu.be/z6klwUxRwQI
// By Amit Agarwal - www.labnol.org
}
The script utilized in the example is extremely generic but very resilient to change because the message is built as a key/value pair of the form fields submitted.
If you use my script you'll have to tweak the for loop if statements to match your fields verbatim. You'll also want to edit the toEmail variable.
Thanks again for the question and answers. I was about to ditch Google Forms as the generic response was never enough for what I was trying to do.
Lastly, in response to the actual problem above "toString of undefined" specifically means one of the form fields was submitted as blank. If I had to guess, I would say the author only used this for forms where all the fields were required or a quick undefined check would've been put in place.
Something like the following would work:
for(var i in headers) {
var formValue = e.namedValues[headers[i]];
var formValueText = "";
if (typeof(formValue) != "undefined") {
formValueText = formValue.toString();
}
message += headers[i] + ' = '+ formvalueText + "\n\n";
}
I haven't tested this precisely but it's a pretty standard way of making sure the object is defined before trying methods like toString() that clearly won't work.
This would also explain Jon Fila's answer. The script blindly assumes all of the header rows in the response are sent by the form. If any of the fields aren't required or the spreadsheet has fields that are no longer in the form, you'll get a lot of undefined objects.
The script could've been coded better but I won't fault the author as it was clearly meant to be a proof of concept only. The fact that they mention the replyTo correction but don't give any examples on implementing it made it perfectly clear.
If this is a Google Form, do you have any extra columns in your spreadsheet that are not on the form? If you delete those extra columns then it started working for me.
You don't need to use a script. Simply go to Tools >> Notification Rules on your Google Spreadsheet. There you can change the settings to receive an email with your desired information every time the document is changed.

How to send an email with attachments in Go

I have found this library and have managed to send an attachment in an empty email but not to combine text and attachments.
https://github.com/sloonz/go-mime-message
How can it be done?
I ended up implementing it myself: https://github.com/scorredoira/email
Usage is very simple:
m := email.NewMessage("Hi", "this is the body")
m.From = "from#example.com"
m.To = []string{"to#example.com"}
err := m.Attach("picture.png")
if err != nil {
log.Println(err)
}
err = email.Send("smtp.gmail.com:587", smtp.PlainAuth("", "user", "password", "smtp.gmail.com"), m)
I created gomail for this purpose. It supports attachments as well as multipart emails and encoding of non-ASCII characters. It is well documented and tested.
Here is an example:
package main
func main() {
m := gomail.NewMessage()
m.SetHeader("From", "alex#example.com")
m.SetHeader("To", "bob#example.com", "cora#example.com")
m.SetAddressHeader("Cc", "dan#example.com", "Dan")
m.SetHeader("Subject", "Hello!")
m.SetBody("text/html", "Hello <b>Bob</b> and <i>Cora</i>!")
m.Attach("/home/Alex/lolcat.jpg")
d := gomail.NewPlainDialer("smtp.example.com", 587, "user", "123456")
// Send the email to Bob, Cora and Dan.
if err := d.DialAndSend(m); err != nil {
panic(err)
}
}
I prefer to use https://github.com/jordan-wright/email for email purposes.
It supports attachments.
Email for humans
The email package is designed to be simple to use, but flexible enough
so as not to be restrictive. The goal is to provide an email interface
for humans.
The email package currently supports the following:
From, To, Bcc, and Cc fields
Email addresses in both "test#example.com" and "First Last " format
Text and HTML Message Body
Attachments
Read Receipts
Custom headers
More to come!
Attachements in the SMTP protocol are sent using a Multipart MIME message.
So I suggest you simply
create a MultipartMessage
set your text in the fist part as a TextMessage (with "Content-Type", "text/plain")
add your attachements as parts using AddPart.