I'm interested in how to pass string (successfully - in UTF8) containing both subject header and body of email to this function:
func sendEmail(body string) {
c, err := smtp.Dial(".....")
if err != nil {
log.Fatal(err)
}
defer c.Close()
// Set the sender and recipient.
c.Mail(".....")
c.Rcpt(".....")
// Send the email body.
wc, err := c.Data()
if err != nil {
log.Fatal(err)
}
defer wc.Close()
buf := bytes.NewBufferString(body)
if _, err = buf.WriteTo(wc); err != nil {
log.Fatal(err)
}
}
And then I've got here subject header and email body;
body := "Subject: Header string which contains ŽČĆŠĐ in name of user " + name + "!\n"
body += "Content-Type: text/html; charset=\"UTF-8\"\r\nContent-Transfer-Encoding: base64\r\n"
body += "String inside email body which also might contain ŽČĆŠĐ" + year_month_day_hour_minute + " - " + end_of_shift
//function call
sendEmail(body)
I've thought it should run ok ...and it really does display correctly subject header string (in utf8) but for some unknown reason the rest of email body gets displayed in junk form.
I've tried to change a few minor details but nothing really changed in principle.
This is my first Go example so I could easily overlook obvious.
Thanks for any thoughts on the matter!
try:
In your text subject use this function
func cSubject(subject string) string {
//return "=?iso-8859-1?Q?" + subject + "?="
return "=?utf-8?q?" + subject + "?="
}
Hi I successfully sent UTF8 email using golang with the following code
func sendContactUs(name string, email string, userInput string) {
// Sender data.
from := "some#email.address"
password := "some password"
// Receiver email address.
to := []string{
"receipient#email.address",
}
// smtp server configuration.
smtpHost := "smtp.gmail.com"
smtpPort := "587"
raw := `Subject: {name} Contact form on Web
Content-Type: text/plain; charset="UTF-8"
Dear Manager,
We receive a a form submission from webpage
name : {name}
email : {email}
message:
{message}
Kind Regards
XXXX Mailing service team.
`
raw = strings.Replace(raw, "{name}", name, -1)
raw = strings.Replace(raw, "{email}", email, -1)
raw = strings.Replace(raw, "{message}", userInput, -1)
// Message.
message := []byte(raw)
// Authentication.
auth := smtp.PlainAuth("", from, password, smtpHost)
// Sending email.
err := smtp.SendMail(smtpHost+":"+smtpPort, auth, from, to, message)
if err != nil {
fmt.Println(err)
return
}
fmt.Println("Email Sent Successfully!")
}
Please note the line with Content-type: it must start at the very beginning.
In other words, it should not have any prepending blank space.
Also, it must have a blank line after it.
It's a working code. please try it out. If you encounter any problems please let me know.
Related
I am trying to pass data from one golang service to another using http.NewRequest(). To do it I used following code:
httpClient := http.Client{}
userserviceUrl := "http://user:7071/checkemail"
form := url.Values{}
form.Set("uuid", uuid)
form.Set("email", email)
b := bytes.NewBufferString(form.Encode())
req, err := http.NewRequest("POST", userserviceUrl, b)
if err != nil {
log.Println(err)
}
opentracing.GlobalTracer().Inject(
validateEmailSpan.Context(),
opentracing.HTTPHeaders,
opentracing.HTTPHeadersCarrier(req.Header))
resp, err := httpClient.Do(req)
//_, err = http.PostForm("http://user:7071/checkemail", url.Values{"uuid": {uuid}, "email": {email}})
if err != nil {
log.Println("Couldnt verify email address user service sends an error : ", err)
}
defer resp.Body.Close()
I got this from Golang: http.NewRequest POST
When I try to dump received data from user service:
req.ParseForm()
log.Println("Form values : ", req.Form)
I get an empty map[]
Here I just try to inject tracing span to my request, previously I have used http.PostForm() to pass data, it worked perfectly. But I have no idea to pass tracing to it.
From the docs for ParseForm:
[...] when the Content-Type is not application/x-www-form-urlencoded, the request Body is not read, and r.PostForm is initialized to a non-nil, empty value.
PostForm sets the Content-Type automatically, but now you have to do it yourself:
req, err := http.NewRequest("POST", userserviceUrl, strings.NewReader(form.Encode()))
// TODO: handle error
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
I'm looking for the cleanest way in Golang to transfer a message through (i.e. act as an SMTP proxy) while performing some manipulation on the message body html (e.g. adding an open tracking pixel - not yet coded).
The net/mail package includes a method ReadMessage that parses mail headers into a map, and gives you an io.Reader for the body. This is necessary to determine the MIME parts of the body for processing, rather than just io.Copying them through. (the simple stub version of this function, shown in the block comment, does just that).
The following function copies an incoming mail "src" to an outgoing mail stream "dest". (The calling code sets these up as DotReader and DotWriter which takes care of most of the "dot" processing needed for RFC5321.
// Processing of email body via IO stream functions
package main
import (
"bufio"
"io"
"log"
"net/mail"
"strings"
)
/* If you just want to pass through the entire mail headers and body, you can just use
the following alernative:
func MailCopy(dst io.Writer, src io.Reader) (int64, error) {
return io.Copy(dst, src)
}
*/
// MailCopy transfers the mail body from downstream (client) to upstream (server)
// The writer will be closed by the parent function, no need to close it here.
func MailCopy(dst io.Writer, src io.Reader) (int64, error) {
var totalWritten int64
const smtpCRLF = "\r\n"
message, err := mail.ReadMessage(bufio.NewReader(src))
if err != nil {
return totalWritten, err
}
// Pass through headers. The m.Header map does not preserve order, but that should not matter.
for hdrType, hdrList := range message.Header {
for _, hdrVal := range hdrList {
hdrLine := hdrType + ": " + hdrVal + smtpCRLF
log.Print("\t", hdrLine)
bytesWritten, err := dst.Write([]byte(hdrLine))
totalWritten += int64(bytesWritten)
if err != nil {
return totalWritten, err
}
}
}
// Blank line denotes end of headers
bytesWritten, err := io.Copy(dst, strings.NewReader(smtpCRLF))
totalWritten += int64(bytesWritten)
if err != nil {
return totalWritten, err
}
// Copy the body
bytesWritten, err = io.Copy(dst, message.Body)
totalWritten += int64(bytesWritten)
if err != nil {
return totalWritten, err
}
return totalWritten, err
}
It does seem necessary to build this, because there is no net/mail.WriteMessage() method.
the header order is always randomised by Golang's map functionality. This seems harmless in my tests
A forced CRLF needs to be put in between the end of the headers and the body, as per RFCs. DotWriter takes care of the terminating dot.
The function shown above works, I was wondering if there is a better way to do this?
I'm trying to figure out how to build multipart/mime envelopes for emails in Go. The following code generates correctly-nested bodies - but the boundaries are not inserted correctly.
You can see a demo on https://play.golang.org/p/XLc4DQFObRn
package main
import (
"bytes"
"fmt"
"io"
"log"
"math/rand"
"mime/multipart"
"mime/quotedprintable"
"net/textproto"
)
// multipart/mixed
// |- multipart/related
// | |- multipart/alternative
// | | |- text/plain
// | | `- text/html
// | `- inlines..
// `- attachments..
func main() {
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
var part io.Writer
var err error
// Text Content
part, err = writer.CreatePart(textproto.MIMEHeader{"Content-Type": {"multipart/alternative"}})
if err != nil {
log.Fatal(err)
}
childWriter := multipart.NewWriter(part)
var subpart io.Writer
for _, contentType := range []string{"text/plain", "text/html"} {
subpart, err = CreateQuoteTypePart(childWriter, contentType)
if err != nil {
log.Fatal(err)
}
_, err := subpart.Write([]byte("This is a line of text that needs to be wrapped by quoted-printable before it goes to far.\r\n\r\n"))
if err != nil {
log.Fatal(err)
}
}
// Attachments
filename := fmt.Sprintf("File_%d.jpg", rand.Int31())
part, err = writer.CreatePart(textproto.MIMEHeader{"Content-Type": {"application/octet-stream"}, "Content-Disposition": {"attachment; filename=" + filename}})
if err != nil {
log.Fatal(err)
}
part.Write([]byte("AABBCCDDEEFF"))
writer.Close()
fmt.Print(`From: Bob <bob#example.com>
To: Alice <alias#example.com>
Subject: Formatted text mail
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary=`)
fmt.Println(writer.Boundary())
fmt.Println(body.String())
}
// https://github.com/domodwyer/mailyak/blob/master/attachments.go#L142
func CreateQuoteTypePart(writer *multipart.Writer, contentType string) (part io.Writer, err error) {
header := textproto.MIMEHeader{
"Content-Type": []string{contentType},
"Content-Transfer-Encoding": []string{"quoted-printable"},
}
part, err = writer.CreatePart(header)
if err != nil {
return
}
part = quotedprintable.NewWriter(part)
return
}
I want to stick to answers from the standard library (stdlib) and avoid third party attempts to wing it.
Unfortunately, the standard library support for writing multi-part MIME messages has a bad API for nesting. The problem is that you have to set the boundary string in the header before creating the writer, but the generated boundary string is obviously not available before creating the writer. So you have to set the boundary strings explicitly.
Here is my solution (runnable in the Go Playground), simplified for brevity. I have chosen to use the outer writer's boundary to set the inner one, and added labels to make it easier to keep track when reading the output.
package main
import ("bytes"; "fmt"; "io"; "log"; "math/rand"; "mime/multipart"; "net/textproto")
// multipart/mixed
// |- multipart/related
// | |- multipart/alternative
// | | |- text/plain
// | | `- text/html
// | `- inlines..
// `- attachments..
func main() {
mixedContent := &bytes.Buffer{}
mixedWriter := multipart.NewWriter(mixedContent)
// related content, inside mixed
var newBoundary = "RELATED-" + mixedWriter.Boundary()
mixedWriter.SetBoundary(first70("MIXED-" + mixedWriter.Boundary()))
relatedWriter, newBoundary := nestedMultipart(mixedWriter, "multipart/related", newBoundary)
altWriter, newBoundary := nestedMultipart(relatedWriter, "multipart/alternative", "ALTERNATIVE-" + newBoundary)
// Actual content alternatives (finally!)
var childContent io.Writer
childContent, _ = altWriter.CreatePart(textproto.MIMEHeader{"Content-Type": {"text/plain"}})
childContent.Write([]byte("This is a line of text\r\n\r\n"))
childContent, _ = altWriter.CreatePart(textproto.MIMEHeader{"Content-Type": {"text/html"}})
childContent.Write([]byte("<html>HTML goes here\r\n</html>\r\n"))
altWriter.Close()
relatedWriter.Close()
// Attachments
filename := fmt.Sprintf("File_%d.jpg", rand.Int31())
var fileContent io.Writer
fileContent, _ = mixedWriter.CreatePart(textproto.MIMEHeader{"Content-Type": {"application/octet-stream"}, "Content-Disposition": {"attachment; filename=" + filename}})
fileContent.Write([]byte("AABBCCDDEEFF"))
mixedWriter.Close()
fmt.Print(`From: Bob <bob#example.com>
To: Alice <alias#example.com>
Subject: Formatted text mail
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary=`)
fmt.Print(mixedWriter.Boundary(), "\n\n")
fmt.Println(mixedContent.String())
}
func nestedMultipart(enclosingWriter *multipart.Writer, contentType, boundary string) (nestedWriter *multipart.Writer, newBoundary string) {
var contentBuffer io.Writer
var err error
boundary = first70(boundary)
contentWithBoundary := contentType + "; boundary=\"" + boundary + "\""
contentBuffer, err = enclosingWriter.CreatePart(textproto.MIMEHeader{"Content-Type": {contentWithBoundary}})
if err != nil {
log.Fatal(err)
}
nestedWriter = multipart.NewWriter(contentBuffer)
newBoundary = nestedWriter.Boundary()
nestedWriter.SetBoundary(boundary)
return
}
func first70(str string) string {
if len(str) > 70 {
return string(str[0:69])
}
return str
}
I am developing a client-server application using RESTful web services.
I want to ask for user input on the client and send it to the server and use that name in the rest of my program but I cannot send the name to the server properly.
Below is a part of my program:
Client:
func main() {
//getting input
fmt.Println("Please enter your name: ")
reader := bufio.NewReader(os.Stdin)
myName, _ := reader.ReadString('\n')
client := &http.Client{
CheckRedirect: nil,
}
reply, err := http.NewRequest("GET", "http://localhost:8080/", nil)
reply.Header.Add("username", myName)
client.Do(reply)
if err != nil {
fmt.Println(err)
}
Server:
func CreateClient(w http.ResponseWriter, r *http.Request) {
clientName := r.Header.Get("username")
fmt.Println(clientName, "---------")//it's empty
cli := &Client{
currentRoom: nil, //starts as nil because the user is not initally in a room
outputChannel: make(chan string),
name: clientName,
}
Members = append(Members, cli)
reply := cli.name
fmt.Fprintf(w, reply)
}
on the client side, reply (reply.Header.Add("username", myName)) has the user name in the header but on the server side clientName (clientName := r.Header.Get("username")) is empty so the rest of my program won't run.
My problem is that I cannot send the user input to the server and take it back on the client side.
Can someone tell me how I can solve the problem?
You may want to have a look at http query string. Wikipedia
Sending the username.
req := http.NewRequest("GET","localhost:8080",nil)
q:=req.URL.Query()
q.Add("username",myName)
req.URL.RawQuery = q.Encode()
Resp,err:=http. Client{}.Do(req)
Recieving the username:
clientName := r.URL.Query()["username"][0]
Note that if your are going to do the same with password or any other sensitive data, please do some research on how to make it secure and DO NOT copy this code.
I'm trying to send an e-mail in Golang and I have a lot of problems with it. I'm new in Go so maybe this is very simply but I cannot find the answer on the doc.
This is what I want to do:
1. get an e-mail from the STDIN
2. parse the e-mail (getting from, to, subject, attachments and so on)
3. send this e-mail (put it again to the queue in local postfix)
I did 1 and 2 but I have a problem with 3th one.
This is what I have now:
package main
import (
"fmt"
"github.com/jhillyerd/go.enmime"
//"github.com/sendgrid/sendgrid-go"
"net/smtp"
"github.com/jordan-wright/email"
"os"
"net/mail"
"io/ioutil"
"bytes"
)
func main() {
mail_stdin, err := ioutil.ReadAll(os.Stdin)
if err != nil {
return
}
// Convert type to io.Reader
buf := bytes.NewBuffer(mail_stdin)
msg, err := mail.ReadMessage(buf)
if err != nil {
return
}
mime, err := enmime.ParseMIMEBody(msg)
if err != nil {
return
}
# saving attachments
for _, value := range mime.Attachments {
fmt.Println(value.FileName())
err := ioutil.WriteFile(value.FileName(), value.Content(), 0664)
if err != nil {
//panic(err)
return
}
fmt.Printf("From: %v\n", msg.Header.Get("From"))
fmt.Printf("Subject: %v\n", mime.GetHeader("Subject"))
fmt.Printf("Text Body: %v chars\n", len(mime.Text))
fmt.Printf("HTML Body: %v chars\n", len(mime.Html))
fmt.Printf("Inlines: %v\n", len(mime.Inlines))
fmt.Printf("Attachments: %v\n", len(mime.Attachments))
fmt.Println(mime.Attachments)
fmt.Println(mime.OtherParts)
fmt.Printf("Attachments: %v\n", mime.Attachments)
}
I already did few tests using: net/smtp, sendgrid-go and jordan-wright/email.
All I want to do is to send an e-mail (without changing anything) from the server to the queue again. Most of those modules needs to have Auth, but I just want to simply send is using sendmail, in the same way as I can do this from the bash:
# echo "test" | mail {address}
Using net/smtp you can do this fairly easily... Assuming you have an smtp server running that you can connect to without authentication. I would guess for what you're trying to accomplish it's actually a lot easier to do through something simple like your gmail ( https://www.digitalocean.com/community/tutorials/how-to-use-google-s-smtp-server )
Anyway, here's a couple code samples to cover either case;
c, err := smtp.Dial("mail.example.com:25")
if err != nil {
log.Fatal(err)
}
defer c.Close()
// Set the sender and recipient.
c.Mail("sender#example.org")
c.Rcpt("recipient#example.net")
// Send the email body.
wc, err := c.Data()
if err != nil {
log.Fatal(err)
}
defer wc.Close()
buf := bytes.NewBufferString("This is the email body.")
if _, err = buf.WriteTo(wc); err != nil {
log.Fatal(err)
}
Alternatively here's a go playground example that uses simple auth; http://play.golang.org/p/ATDCgJGKZ3 unless you've already got an smtp server running on your dev box following something like that will probably be a lot easier.