<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Winni Neessen</title>
    <description>The latest articles on DEV Community by Winni Neessen (@wneessen).</description>
    <link>https://dev.to/wneessen</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F915297%2F2e6bd8a2-ede1-43b9-b251-ba89ab2cb7d1.jpeg</url>
      <title>DEV Community: Winni Neessen</title>
      <link>https://dev.to/wneessen</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/wneessen"/>
    <language>en</language>
    <item>
      <title>User permission checking in Go</title>
      <dc:creator>Winni Neessen</dc:creator>
      <pubDate>Sat, 12 Nov 2022 21:14:30 +0000</pubDate>
      <link>https://dev.to/wneessen/user-permission-checking-in-go-2ohp</link>
      <guid>https://dev.to/wneessen/user-permission-checking-in-go-2ohp</guid>
      <description>&lt;p&gt;&lt;small&gt;This article was &lt;a href="https://pebcak.de/posts/2022/11/12/check-file-perms-in-go/"&gt;originally published&lt;/a&gt; on my personal blog.&lt;/small&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;While working on my &lt;a href="https://github.com/wneessen/go-pf"&gt;go-pf&lt;/a&gt; module, I was faced with the problem to make sure that the &lt;code&gt;/dev/pf&lt;/code&gt; device is readable and writable. While other languages like the Shell or Perl offer test functions to check if the current user/process has read/write/exec permissions on the specific file, in Go this task is not trivial.&lt;/p&gt;

&lt;p&gt;Here is how we can do it with Perl:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env perl&lt;/span&gt;

&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test.txt&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!-&lt;/span&gt;&lt;span class="nv"&gt;r&lt;/span&gt; &lt;span class="nv"&gt;$file&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!-&lt;/span&gt;&lt;span class="nv"&gt;w&lt;/span&gt; &lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="nv"&gt;$file&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; is not read- and/or writable to the process&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
    &lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;We're all good!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we run a quick one-liner in the Shell then, we can see how the script works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="k"&gt;for &lt;/span&gt;i &lt;span class="k"&gt;in &lt;/span&gt;100 200 400 500 600 700&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"chmod: &lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nb"&gt;chmod&lt;/span&gt; &lt;span class="nv"&gt;$i&lt;/span&gt; test.txt&lt;span class="p"&gt;;&lt;/span&gt; perl test.pl&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;done
&lt;/span&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt;: 100
test.txt is not read- and/or writable to the process
&lt;span class="nb"&gt;chmod&lt;/span&gt;: 200
test.txt is not read- and/or writable to the process
&lt;span class="nb"&gt;chmod&lt;/span&gt;: 400
test.txt is not read- and/or writable to the process
&lt;span class="nb"&gt;chmod&lt;/span&gt;: 500
test.txt is not read- and/or writable to the process
&lt;span class="nb"&gt;chmod&lt;/span&gt;: 600
We&lt;span class="s1"&gt;'re all good!
chmod: 700
We'&lt;/span&gt;re all good!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Go we would need to rely on &lt;a href="https://pkg.go.dev/os#Lstat"&gt;os.Lstat&lt;/a&gt; which would then provide us with the &lt;code&gt;Mode().Perm()&lt;/code&gt; method, which we could use to get the file mode of the file. But that is only half the rent. Just because the file might return a file mode of &lt;code&gt;700&lt;/code&gt;, which basically would mean that read and write permissions are given, the file might not be owned by us. It gets even more complicated when we need to take in account that we also have group and "other" file permissions. &lt;/p&gt;

&lt;h2&gt;
  
  
  The solution
&lt;/h2&gt;

&lt;p&gt;Since I couldn't find a ready-made solution, I made it my task to solve the problem - preferably in an equally simple way, such as in Perl.&lt;/p&gt;

&lt;p&gt;As mentioned, we can utilize &lt;code&gt;os.Lstat&lt;/code&gt; as our starting point. With the file permissions and some bit shifting, we can easily figure out if a file is read/write/executable for "other", group and user. With this information at hand, the next step is to figure out the owner and the group of the file in question. For UNIX-like operating systems, Go provides us with the &lt;code&gt;Sys()&lt;/code&gt; method on our &lt;code&gt;FileInfo&lt;/code&gt; that is returned by &lt;code&gt;os.Lstat&lt;/code&gt;. We can try to type-cast the result of &lt;code&gt;Sys()&lt;/code&gt; into a &lt;a href="https://pkg.go.dev/syscall#Stat_t"&gt;*syscall.Stat_t&lt;/a&gt; pointer. If this succeeds, we will get the information that we need with the &lt;code&gt;Uid&lt;/code&gt; and &lt;code&gt;Gid&lt;/code&gt; properties. &lt;/p&gt;

&lt;p&gt;Problem number one is solved, we can see who owns the file and check if our current user is indeed the owner. The &lt;a href="https://pkg.go.dev/os/user#Current"&gt;os/user.Current&lt;/a&gt; method can help us with that. Our next task is group ownership - again this is not a trivial task, since a user can be part of several groups. Again the Go standard library provides us with the tools we need in form of the &lt;a href="https://pkg.go.dev/os/user#User.GroupIds"&gt;User.GroupIds&lt;/a&gt; method, which will give us a list of groups that our user is part of. With this list, it is fairly easy to figure out if our user is part of the group of the file. The second problem is solved as well. For the "other" permission we can again work off with some bit-shifting. &lt;/p&gt;

&lt;h2&gt;
  
  
  go-fileperm
&lt;/h2&gt;

&lt;p&gt;You probably guessed already, that I built something out of all of this. &lt;a href="//https//github.com/wneessen/go-fileperm"&gt;go-fileperm&lt;/a&gt; uses all the information I discussed before into one simple-to-use Go module. Let's have a look.&lt;/p&gt;

&lt;p&gt;First of all, we use the &lt;code&gt;New()&lt;/code&gt; method to get an instance of the type &lt;code&gt;UserPerm&lt;/code&gt;. &lt;code&gt;New&lt;/code&gt; takes a string as an argument, which is the path to the file in question. If this succeeds, the module will provide you with a couple of methods to check the file access permissions (all of which return a boolean value):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;UserExecutable()&lt;/code&gt;: returns true if the current user/process has execution permission on the file in question.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;UserWritable()&lt;/code&gt;: returns true if the current user/process has write permission on the file in question.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;UserReadable()&lt;/code&gt;: returns true if the current user/process has read permission on the file in question.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;UserWriteExecutable()&lt;/code&gt;: returns true if the current user/process has write and execution permission on the 
file in question.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;UserReadExecutable()&lt;/code&gt;: returns true if the current user/process has read and execution permission on the
file in question.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;UserWriteReadExecutable()&lt;/code&gt;: returns true if the current user/process has read, write and execution permission 
on the file in question.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Performance
&lt;/h2&gt;

&lt;p&gt;Since go-fileperm mostly makes use of bit-shifting, the performance of the module is pretty fast. Also, we work allocation-free, which is always a plus :)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;goos: darwin
goarch: arm64
pkg: github.com/wneessen/go-fileperm
BenchmarkPermUser_UserReadable
BenchmarkPermUser_UserReadable-8                 7364846               143.6 ns/op             0 B/op          0 allocs/op
BenchmarkPermUser_UserWritable
BenchmarkPermUser_UserWritable-8                 7803267               154.9 ns/op             0 B/op          0 allocs/op
BenchmarkPermUser_UserExecutable
BenchmarkPermUser_UserExecutable-8               7922624               149.2 ns/op             0 B/op          0 allocs/op
BenchmarkPermUser_UserWriteReadable
BenchmarkPermUser_UserWriteReadable-8            6494815               186.1 ns/op             0 B/op          0 allocs/op
BenchmarkPermUser_UserWriteExecutable
BenchmarkPermUser_UserWriteExecutable-8          6590229               181.0 ns/op             0 B/op          0 allocs/op
BenchmarkPermUser_UserReadExecutable
BenchmarkPermUser_UserReadExecutable-8           6190532               184.7 ns/op             0 B/op          0 allocs/op
BenchmarkPermUser_UserWriteReadExecutable
BenchmarkPermUser_UserWriteReadExecutable-8      5728713               208.8 ns/op             0 B/op          0 allocs/op
PASS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Full code example
&lt;/h2&gt;

&lt;p&gt;Let's check out a full code example and apply our one-liner that we used in the beginning.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"log"&lt;/span&gt;

    &lt;span class="s"&gt;"github.com/wneessen/go-fileperm"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;fileperm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"test.txt"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to create UserPerm instance: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"test.txt is user-readable:              %t&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserReadable&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"test.txt is user-writable:              %t&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserWritable&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"test.txt is user-executable:            %t&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserExecutable&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"test.txt is user-read/writable:         %t&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserWriteReadable&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"test.txt is user-read/executable:       %t&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserReadExecutable&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"test.txt is user-write/executable:      %t&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserWriteExecutable&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"test.txt is user-read/write/executable: %t&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserWriteReadExecutable&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="k"&gt;for &lt;/span&gt;i &lt;span class="k"&gt;in &lt;/span&gt;100 200 400 500 600 700&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"chmod: &lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nb"&gt;chmod&lt;/span&gt; &lt;span class="nv"&gt;$i&lt;/span&gt; test.txt&lt;span class="p"&gt;;&lt;/span&gt; go run main.go&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;done

&lt;/span&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt;: 100
test.txt is user-readable:              &lt;span class="nb"&gt;false
&lt;/span&gt;test.txt is user-writable:              &lt;span class="nb"&gt;false
&lt;/span&gt;test.txt is user-executable:            &lt;span class="nb"&gt;true
&lt;/span&gt;test.txt is user-read/writable:         &lt;span class="nb"&gt;false
&lt;/span&gt;test.txt is user-read/executable:       &lt;span class="nb"&gt;false
&lt;/span&gt;test.txt is user-write/executable:      &lt;span class="nb"&gt;false
&lt;/span&gt;test.txt is user-read/write/executable: &lt;span class="nb"&gt;false
chmod&lt;/span&gt;: 200
test.txt is user-readable:              &lt;span class="nb"&gt;false
&lt;/span&gt;test.txt is user-writable:              &lt;span class="nb"&gt;true
&lt;/span&gt;test.txt is user-executable:            &lt;span class="nb"&gt;false
&lt;/span&gt;test.txt is user-read/writable:         &lt;span class="nb"&gt;false
&lt;/span&gt;test.txt is user-read/executable:       &lt;span class="nb"&gt;false
&lt;/span&gt;test.txt is user-write/executable:      &lt;span class="nb"&gt;false
&lt;/span&gt;test.txt is user-read/write/executable: &lt;span class="nb"&gt;false
chmod&lt;/span&gt;: 400
test.txt is user-readable:              &lt;span class="nb"&gt;true
&lt;/span&gt;test.txt is user-writable:              &lt;span class="nb"&gt;false
&lt;/span&gt;test.txt is user-executable:            &lt;span class="nb"&gt;false
&lt;/span&gt;test.txt is user-read/writable:         &lt;span class="nb"&gt;false
&lt;/span&gt;test.txt is user-read/executable:       &lt;span class="nb"&gt;false
&lt;/span&gt;test.txt is user-write/executable:      &lt;span class="nb"&gt;false
&lt;/span&gt;test.txt is user-read/write/executable: &lt;span class="nb"&gt;false
chmod&lt;/span&gt;: 500
test.txt is user-readable:              &lt;span class="nb"&gt;true
&lt;/span&gt;test.txt is user-writable:              &lt;span class="nb"&gt;false
&lt;/span&gt;test.txt is user-executable:            &lt;span class="nb"&gt;true
&lt;/span&gt;test.txt is user-read/writable:         &lt;span class="nb"&gt;false
&lt;/span&gt;test.txt is user-read/executable:       &lt;span class="nb"&gt;true
&lt;/span&gt;test.txt is user-write/executable:      &lt;span class="nb"&gt;false
&lt;/span&gt;test.txt is user-read/write/executable: &lt;span class="nb"&gt;false
chmod&lt;/span&gt;: 600
test.txt is user-readable:              &lt;span class="nb"&gt;true
&lt;/span&gt;test.txt is user-writable:              &lt;span class="nb"&gt;true
&lt;/span&gt;test.txt is user-executable:            &lt;span class="nb"&gt;false
&lt;/span&gt;test.txt is user-read/writable:         &lt;span class="nb"&gt;true
&lt;/span&gt;test.txt is user-read/executable:       &lt;span class="nb"&gt;false
&lt;/span&gt;test.txt is user-write/executable:      &lt;span class="nb"&gt;false
&lt;/span&gt;test.txt is user-read/write/executable: &lt;span class="nb"&gt;false
chmod&lt;/span&gt;: 700
test.txt is user-readable:              &lt;span class="nb"&gt;true
&lt;/span&gt;test.txt is user-writable:              &lt;span class="nb"&gt;true
&lt;/span&gt;test.txt is user-executable:            &lt;span class="nb"&gt;true
&lt;/span&gt;test.txt is user-read/writable:         &lt;span class="nb"&gt;true
&lt;/span&gt;test.txt is user-read/executable:       &lt;span class="nb"&gt;true
&lt;/span&gt;test.txt is user-write/executable:      &lt;span class="nb"&gt;true
&lt;/span&gt;test.txt is user-read/write/executable: &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;As you can see, the module is pretty easy to use and hopefully will be a helpful tool for some of you. As usual, I've published it on GitHub under the MIT license, so feel free to give it a try or even contribute if you think there is things that need improvements.&lt;/p&gt;

</description>
      <category>go</category>
      <category>perm</category>
      <category>file</category>
    </item>
    <item>
      <title>Sending mails in Go the easy way</title>
      <dc:creator>Winni Neessen</dc:creator>
      <pubDate>Sat, 08 Oct 2022 11:36:03 +0000</pubDate>
      <link>https://dev.to/wneessen/sending-mails-in-go-the-easy-way-1lm7</link>
      <guid>https://dev.to/wneessen/sending-mails-in-go-the-easy-way-1lm7</guid>
      <description>&lt;p&gt;I recently read &lt;a href="https://dev.to/nataliiapolomkina/how-to-send-emails-in-go-49o9"&gt;this article&lt;/a&gt; on dev.to about "How to Send Emails in Go". It seems to be a copy from a &lt;a href="https://mailtrap.io/blog/golang-send-email/"&gt;blog post&lt;/a&gt; from mailtrap.io. &lt;/p&gt;

&lt;p&gt;While the article is certainly not wrong on what is written there, it seems like its main intention is to make the point that it's easier to use a 3rd party mail service - which is perfectly fine... yet, I found the conclusion a bit baffleing. In the article it says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This wraps up our rather quick guide to sending emails in Golang. As you can see, the choice comes down to either utilizing basic in-built functionalities of Go or connecting to 3rd parties to send emails on your behalf.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I have to disagree with this, since there are lots of good Go mail libaries that really make your job of sending mail so much easier. &lt;/p&gt;

&lt;h2&gt;
  
  
  go-mail makes it easy for you
&lt;/h2&gt;

&lt;p&gt;As backbone for my form mailing microservice &lt;a href="https://github.com/wneessen/js-mailer"&gt;js-mailer&lt;/a&gt;, I've created &lt;a href="https://github.com/wneessen/go-mail"&gt;go-mail&lt;/a&gt; as a state of the art Go mail libarary that is comprehensive, yet easy to use.&lt;/p&gt;

&lt;p&gt;go-mail consists of two main components. The &lt;code&gt;Msg&lt;/code&gt; representing the mail message and everything related to it and the &lt;code&gt;Client&lt;/code&gt; which is handling the mail server communication and the delivery of the &lt;code&gt;Msg&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Since the original article first mentions &lt;code&gt;smtp.SendMail&lt;/code&gt;, let's have a look at how we would archive the same with go-mail.&lt;/p&gt;

&lt;p&gt;The original example creates a simple mail from &lt;code&gt;bill@gates.com&lt;/code&gt; delivered to &lt;code&gt;bill@gates.com&lt;/code&gt; with a simple subject &lt;code&gt;why are you not using Mailtrap yet?&lt;/code&gt; and a mail body saying &lt;code&gt;Here’s the space for our great sales pitch&lt;/code&gt;. The whole thing is delivered via SMTP server &lt;code&gt;smtp.mailtrap.io:25&lt;/code&gt; and using SMTP Plain Authentication.&lt;/p&gt;

&lt;p&gt;With go-mail it would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/wneessen/go-mail"&lt;/span&gt;
    &lt;span class="s"&gt;"log"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// First we create a mail message&lt;/span&gt;
    &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;mail&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewMsg&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;From&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"bill@gates.com"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to set From address: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;To&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"bill@gates.com"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to set To address: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Subject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Why are you not using go-mail yet?"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetBodyString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mail&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TypeTextPlain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"You won't need a sales pitch. It's FOSS."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Secondly the mail client&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;mail&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"smtp.mailtrap.io"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="n"&gt;mail&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithPort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;25&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;mail&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithSMTPAuth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mail&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SMTPAuthPlain&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
        &lt;span class="n"&gt;mail&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithUsername&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"piotr@mailtrap.io"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;mail&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithPassword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"extremely_secret_pass"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to create mail client: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Finally let's send out the mail&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DialAndSend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to send mail: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first glance this might look like much more code, but while with &lt;code&gt;net/smtp&lt;/code&gt; and &lt;code&gt;smtp.SendMail&lt;/code&gt; you need to make sure that all parameters (like mail addresses) are syntactically right and line breaks are put in correctly, go-mail will take care of all of this for you. Additionally the syntax is self-explainatory and easy to understand.&lt;/p&gt;

&lt;h2&gt;
  
  
  Authentication
&lt;/h2&gt;

&lt;p&gt;The original article talks about the authentication methods that can be used. We make use of the &lt;a href="https://pkg.go.dev/net/smtp#Auth"&gt;smtp.Auth&lt;/a&gt; interface, which allows the user to implement their own authentication methods and use them with go-mail without issues. &lt;/p&gt;

&lt;p&gt;This means, analogous to &lt;code&gt;net/smtp&lt;/code&gt;, go-mail supports SMTP PLAIN and CRAM-MD5 authentication. Additionally I've also added support for SMTP LOGIN (which is similar to SMTP PLAIN but not the same).&lt;/p&gt;

&lt;h2&gt;
  
  
  TLS
&lt;/h2&gt;

&lt;p&gt;Nowadays, you want to make sure that your authentication is secure. SMTP PLAIN and LOGIN basically send your username and password in plaintext over the wire. Therfore we need to make use of transport encryption using TLS.&lt;/p&gt;

&lt;p&gt;I am a firm believer in strong encryption by default and that nowadays, with all the easy tools like Let's Encrypt and co., there is basically no excuse to not use TLS for any connection anymore. For that reason, go-mail defaults to mandatory TLS in the client - which means the client will fail if the server does not support STARTTLS for the connection. Still you have the option to set the client to opportunistic TLS (use TLS if available, otherwise don't) or disable TLS completely.&lt;/p&gt;

&lt;p&gt;To do so, all you need to do is giving the &lt;code&gt;NewClient()&lt;/code&gt; method an additional option.&lt;/p&gt;

&lt;p&gt;Re-using the code from our initial example, it would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;mail&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"smtp.mailtrap.io"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;mail&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithPort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;25&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;mail&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithSMTPAuth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mail&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SMTPAuthPlain&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
    &lt;span class="n"&gt;mail&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithUsername&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"piotr@mailtrap.io"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
    &lt;span class="n"&gt;mail&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithPassword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"extremely_secret_pass"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;mail&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithTLSPolicy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mail&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TLSOpportunistic&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Multiple recipients and (B)CC
&lt;/h2&gt;

&lt;p&gt;Next the article mentions that things get a bit more sophisticated when it comes to mutliple recipients. Not for go-mail though. The &lt;code&gt;Msg.To()&lt;/code&gt; method allows to provide multiple recipients. So for our initial example all we would need to do is the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;To&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"bill@gates.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"stevie@microsoft.com"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to set To address: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Easy, isn't it?&lt;/p&gt;

&lt;p&gt;The original article now wants to seperate the 2nd address from the To-Address list. No problem! We have &lt;code&gt;Msg.Cc()&lt;/code&gt; in go-mail. Which makes sure that envelope address header and mail address header are setup correctly for this operation. Here is what our code would look now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;To&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"bill@gates.com"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to set To address: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Cc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"stevie@microsoft.com"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to set CC address: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We still get the benefit from go-mails syntax checks and we don't need to care about any newlines or formating.&lt;/p&gt;

&lt;p&gt;Finally the article doesn’t want Bill to know that Steve knows. So they separate envelope recipients from the mail header recipients - which makes the code look really confusing in my opinion. go-mail has a much more comfortable solution: &lt;code&gt;Msg.Bcc()&lt;/code&gt;. Same as you would set a blind carbon copy recipient in your mail client, go-mail takes care of all the bells and whistles.&lt;/p&gt;

&lt;p&gt;Here is our new code snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;To&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"bill@gates.com"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to set To address: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bcc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"stevie@microsoft.com"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to set BCC address: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yes, it's really as easy as that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quality of Life
&lt;/h2&gt;

&lt;p&gt;When I initially created go-mail one of my main goals was to make go-mail act similar to a normal mail user agent (MUA). Hence go-mail has a lot of - what I would call - "Quality of Life" methods. Things that you would likly be able to do yourself without go-mail providing these methods but it's so much easier to not having to think about it. Let's for example look at mail importance.&lt;/p&gt;

&lt;p&gt;Mails can have importance flags. Unforuntately not every mail client handles those in the same way. It's all depending on the correct mail headers and the values you provide them. To make the user's life easier, go-mail provides a &lt;code&gt;Msg.SetImportance()&lt;/code&gt; method. All you need to do is provide the importance you like to set for your message and go-mail will take care of the rest.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetImportance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mail&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ImportanceHigh&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  We can do much more
&lt;/h2&gt;

&lt;p&gt;In the final chapter of the article it switches from Go's own tools to using 3rd party APIs for sending mails, giving you access to i. e. "beautiful HTML mails" or "message previews". Let's address those two points in terms of go-mail.&lt;/p&gt;

&lt;h3&gt;
  
  
  HTML mails
&lt;/h3&gt;

&lt;p&gt;go-mail is built with full MIME and multipart support. This means it takes care of proper MIME encoding as well as being able to handle multiple mail parts like mail body + attachment. Not only this, we have built in support for Go's text/template and html/template systems. &lt;/p&gt;

&lt;p&gt;To send a HTML mail, all we would need to do is change one line in our initial example code:&lt;/p&gt;

&lt;p&gt;Replace:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetBodyString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mail&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TypeTextPlain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"You won't need a sales pitch. It's FOSS."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetBodyString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mail&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TypeTextHTML&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;h1&amp;gt;You won't need a sales pitch. It's FOSS.&amp;lt;/h1&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's assume we live in a modern world, where mails not only consist of plain text or HTML, but we let the client decide what to show instead. For this we can make use of alternative mail body parts. Let's have a look how this would look in code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetBodyString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mail&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TypeTextHTML&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;h1&amp;gt;You won't need a sales pitch. It's FOSS and HTML!&amp;lt;/h1&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddAlternativeString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mail&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TypeTextPlain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"You won't need a sales pitch. It's FOSS and plain text!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A more advanced example would be the use of HTML templates. Let's have a quick look on how this would work.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"html/template"&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;MyStruct&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Placeholder&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;MyStruct&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Placeholder&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Teststring"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;tpl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"This is a {{.Placeholder}}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to parse HTML template: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetBodyHTMLTemplate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tpl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to set HTML template mail body: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we create a new example struct that would represent our template data. We create a new &lt;code&gt;html/template&lt;/code&gt; template and add some example text with placeholders that would fit our template data. All that's left is to use &lt;code&gt;Msg.SetBodyHTMLTemplate()&lt;/code&gt; with our template and data and go-mail will take care of the rest.&lt;/p&gt;

&lt;p&gt;In fact go-mail has support for many different kinds of attachments. Be it simple files from the local file system, from an &lt;code&gt;io.Reader&lt;/code&gt; interface, from an &lt;code&gt;embed.FS&lt;/code&gt; or the already mentioned template packages.&lt;/p&gt;

&lt;h3&gt;
  
  
  Message preview
&lt;/h3&gt;

&lt;p&gt;I already mentioned that go-mail consists of two main components. The Client and the Msg. The beauty of this is, that we have implemented a &lt;code&gt;io.WriteTo&lt;/code&gt; interface into the &lt;code&gt;Msg&lt;/code&gt;. This means, we get access to our mail message without having to pump it through our &lt;code&gt;Client&lt;/code&gt;. Not only that, we also have methods on the &lt;code&gt;Msg&lt;/code&gt; which allows us to store the mail directly into a file or push it to a &lt;code&gt;io.Writer&lt;/code&gt; interface. Let's have a closer look...&lt;/p&gt;

&lt;p&gt;If you work on a unix like OS (Linux, *BSD, MacOS) you probably know that there a special devices for standard input and output. One of them is &lt;code&gt;/dev/stdout&lt;/code&gt; which is your standard output on a terminal console. In Go this interface is represented by the &lt;code&gt;os.Stdout&lt;/code&gt; file pointer. Since it satisfies the &lt;code&gt;io.Writer&lt;/code&gt; interface, it makes it super easy for us to preview a mail. &lt;/p&gt;

&lt;p&gt;Check this out:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stdout&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to write mail to STDOUT: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We tell go-mail to write our mail message to STDOUT and it will perform all it's magic first and just pump the whole output into the STDOUT file. The output would look similar to this in my linux console:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;go run main.go

Date: Sat, 08 Oct 2022 12:47:50 +0200
MIME-Version: 1.0
Message-ID: &amp;lt;116004.6075668864260473870.1665226070@arch-vm.local.host&amp;gt;
Subject: Why are you not using go-mail yet?
User-Agent: go-mail v0.2.9 // https://github.com/wneessen/go-mail
X-Mailer: go-mail v0.2.9 // https://github.com/wneessen/go-mail
From: &amp;lt;bill@gates.com&amp;gt;
To: &amp;lt;bill@gates.com&amp;gt;
Content-Type: multipart/alternative&lt;span class="p"&gt;;&lt;/span&gt;
 &lt;span class="nv"&gt;boundary&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;9c5a427bc18e45ff56e0b8f7053cddceaca54a5c985a425213544ab7977f

&lt;span class="nt"&gt;--9c5a427bc18e45ff56e0b8f7053cddceaca54a5c985a425213544ab7977f&lt;/span&gt;
Content-Transfer-Encoding: quoted-printable
Content-Type: text/html&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;charset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;UTF-8

&amp;lt;h1&amp;gt;You won&lt;span class="s1"&gt;'t need a sales pitch. It'&lt;/span&gt;s FOSS and HTML!&amp;lt;/h1&amp;gt;
&lt;span class="nt"&gt;--9c5a427bc18e45ff56e0b8f7053cddceaca54a5c985a425213544ab7977f&lt;/span&gt;
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;charset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;UTF-8

You won&lt;span class="s1"&gt;'t need a sales pitch. It'&lt;/span&gt;s FOSS and plain text!
&lt;span class="nt"&gt;--9c5a427bc18e45ff56e0b8f7053cddceaca54a5c985a425213544ab7977f--&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See how go-mail internally took care of the encoding, the formating, the different mail parts? That's the beauty of this libary. You, the user, only needs to take care of what is important to you and go-mail makes sure it complies to the corresponding mail RFCs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Local mail server
&lt;/h3&gt;

&lt;p&gt;Sometimes you don't have an external mail service to sent you mails from and all you want to do is using a local sendmail client to deliver the mail. go-mail has you covered here as well. We provide access to local sendmail programs using its own &lt;code&gt;Msg.WriteToSendmail()&lt;/code&gt; method (or &lt;code&gt;Msg.WriteToSendmailWithCommand()&lt;/code&gt; if your sendmail binary is not found in &lt;code&gt;/usr/sbin/sendmail&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;We can basically use the same code syntax as in our previous example, just with the new method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteToSendmail&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to write mail to local sendmail: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Middleware
&lt;/h2&gt;

&lt;p&gt;One of the principles that I introduced when I wrote go-mail was that I want to only rely on the Go standard library and not introduce any 3rd party code. This we go-mail can concentrate on it's main functionality: sending mails.&lt;/p&gt;

&lt;p&gt;With the v0.2.8 release, we received a PR for an awesome feature though: &lt;code&gt;Msg.Middleware&lt;/code&gt;. The middleware interface allows the user to implement their own methods on the Msg without having the restriction of only the Go standard library. The interface is super easy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Middleware&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Msg&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All your code needs to do is provide a &lt;code&gt;Handle&lt;/code&gt; method that takes a &lt;code&gt;Msg&lt;/code&gt; pointer and in the end returns the &lt;code&gt;Msg&lt;/code&gt; pointer again. What happens with the mail message in between is totally up to you.&lt;/p&gt;

&lt;p&gt;Inspired by this cool feature, I started an additional GH repository called &lt;a href="https://github.com/wneessen/go-mail-middleware"&gt;go-mail-middleware&lt;/a&gt;, which is supposed to be a collection of useful middlwares that interact with go-mail. For now I've only added a simple subject capitalization middleware but I am hoping that other users will provide cool stuff there as well in the future. If you have a cool idea for a mail middleware, a PR is more than welcome.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;As you can hopefully see, go-mail is a powerful tool in your Go toolbox. It not only makes sure that your mails comply with the mail RFCs it also has many small "Quality of Life" features which will make your work with mails in Go so much easier. Check out the &lt;a href="https://pkg.go.dev/github.com/wneessen/go-mail"&gt;full documentation&lt;/a&gt; and find out how go-mail can make your life easier. &lt;/p&gt;

&lt;p&gt;The project might be relatively new but we already have a healthy community and according to the Github stats, a couple of projects already rely on go-mail for their code.&lt;/p&gt;

&lt;p&gt;We also have a &lt;a href="https://discord.gg/zSUeBrsFPB"&gt;discord channel&lt;/a&gt; on the official Gopher Discord server. Feel free to stop by and say hello!&lt;/p&gt;

</description>
      <category>go</category>
      <category>email</category>
      <category>mail</category>
    </item>
    <item>
      <title>Sending (form-)mails from static websites with Go</title>
      <dc:creator>Winni Neessen</dc:creator>
      <pubDate>Thu, 25 Aug 2022 15:59:37 +0000</pubDate>
      <link>https://dev.to/wneessen/sending-form-mails-from-static-websites-with-go-2425</link>
      <guid>https://dev.to/wneessen/sending-form-mails-from-static-websites-with-go-2425</guid>
      <description>&lt;h2&gt;
  
  
  From HTML to Wordpress to Hugo
&lt;/h2&gt;

&lt;p&gt;For over 7 years, I've been maintaining the website of a non-profit organisation. When I took over this task from the previous webmaster, the page was a collection of manually generated and maintained HTML pages. Since I didn’t want to manually write HTML on each page for every change that needed to be done, I decided to rebuild the whole site in Wordpress.&lt;/p&gt;

&lt;p&gt;Even though this worked pretty well, over the years I started to dislike Wordpress. Also with all the needed plugins, the site became horribly slow (4-5 seconds per requests - I’ve never really figured out which plugin caused this slowness). So eventually I decided to replace the Wordpress with a static page generator: &lt;a href="https://gohugo.io/"&gt;Hugo&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sending mails from HTML forms
&lt;/h2&gt;

&lt;p&gt;Hugo is great and fast and I really enjoy working with it. It was the right decision. Now, the page is responsive, fast and easy to maintain.&lt;/p&gt;

&lt;p&gt;Yet, one thing I couldn’t easily accomplish with Hugo was sending mails from contact forms - basically a form mailer. With Wordpress, since it’s PHP under the hood on the server side, this is pretty easy. But with Hugo, the pages are static HTML. &lt;/p&gt;

&lt;p&gt;So I had to use JavaScript and some kind of form mailer to send contact form requests. There are 3rd party services like &lt;a href="https://formspree.io/"&gt;https://formspree.io/&lt;/a&gt; that are specialized on this, but since I don’t wanna invest money just to send forms and I also don’t trust the data privacy of such services (GDPR is a big thing in the EU you know 😉), I decided to write my own little web service for it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing js-mailer
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/wneessen/js-mailer"&gt;js-mailer&lt;/a&gt; is a very simple, yet powerful, web service writting in Go that allows static websites to send forms via JavaScript’s &lt;code&gt;fetch()&lt;/code&gt; or &lt;code&gt;XMLHttpRequest&lt;/code&gt; APIs.&lt;/p&gt;

&lt;p&gt;It follows a two-step workflow. First your JavaScript requests a token from the API using the &lt;code&gt;/api/v1/token&lt;/code&gt; endpoint. If the request is valid and website is authorized to request a token, the API will respond with a &lt;code&gt;TokenResponseJson&lt;/code&gt;. This holds some data, which needs to be included into your form as hidden inputs. It will also provide a submission URL endpoint &lt;code&gt;/api/v1/send/&amp;lt;formid&amp;gt;/&amp;lt;token&amp;gt;&lt;/code&gt; that can be used as action in your form. Once the form is submitted, the API will then validate that all submitted data is correct and submit the form data to the configured recipients.&lt;/p&gt;

&lt;p&gt;What started as a quick and dirty “I want to send HTML forms as mail” service, quickly transformed into a fully flegged web service. At the time of this post, the service supports the following features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Single-binary webservice&lt;/li&gt;
&lt;li&gt;Multi-form support&lt;/li&gt;
&lt;li&gt;Multiple recipients per form&lt;/li&gt;
&lt;li&gt;Only display form-fields that are configured in for the form in the resulting mail&lt;/li&gt;
&lt;li&gt;Check for required form fields&lt;/li&gt;
&lt;li&gt;Anti-SPAM functionality via built-in, auto-expiring and single-use security token feature&lt;/li&gt;
&lt;li&gt;Anti-SPAM functionality via honeypot fields&lt;/li&gt;
&lt;li&gt;Limit form access to specific domains&lt;/li&gt;
&lt;li&gt;Per-form mail server configuration&lt;/li&gt;
&lt;li&gt;hCaptcha support&lt;/li&gt;
&lt;li&gt;reCaptcha v2 support&lt;/li&gt;
&lt;li&gt;Form field type validation (text, email, number, bool)&lt;/li&gt;
&lt;li&gt;Confirmation mail to poster&lt;/li&gt;
&lt;li&gt;Custom Reply-To header based on sending mail address&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is FOSS and can be found on &lt;a href="https://github.com/wneessen/js-mailer"&gt;Github&lt;/a&gt;. Maybe it can help you with a similar problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sending mails with Go
&lt;/h2&gt;

&lt;p&gt;In the first iterations of &lt;code&gt;js-mailer&lt;/code&gt; I used the popular &lt;a href="https://github.com/go-gomail/gomail"&gt;go-gomail/gomail&lt;/a&gt; package for handling the mail sending part. Unfortunately the project isn't maintained anymore and uses some pretty outdated opinions on how to handle the mail sending. &lt;/p&gt;

&lt;p&gt;Due to the above mentioned reasons and the lack of proper alternatives decided to write my own Go mail library. On a long weekend I started working on &lt;a href="https://github.com/wneessen/go-mail"&gt;wneessen/go-mail&lt;/a&gt; and in the night of Sunday I had a kind of working prototype and I implemented it with &lt;code&gt;js-mailer&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Meanwhile &lt;code&gt;go-mail&lt;/code&gt; has grown to what I would call a pretty comprehensive library for all kinds of "sending mails with Go" tasks and the Github issues page shows that people start using it and request things they'd like to see as part of &lt;code&gt;go-mail&lt;/code&gt;. The feature list of &lt;code&gt;go-mail&lt;/code&gt; currently holds these pinpoints:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Only Standard Library dependant&lt;/li&gt;
&lt;li&gt;Modern, idiomatic Go&lt;/li&gt;
&lt;li&gt;Sane and secure defaults&lt;/li&gt;
&lt;li&gt;Explicit SSL/TLS support&lt;/li&gt;
&lt;li&gt;Implicit StartTLS support with different policies&lt;/li&gt;
&lt;li&gt;Makes use of contexts for a better control flow and timeout/cancelation handling&lt;/li&gt;
&lt;li&gt;SMTP Auth support (LOGIN, PLAIN, CRAM-MD)&lt;/li&gt;
&lt;li&gt;RFC5322 compliant mail address validation&lt;/li&gt;
&lt;li&gt;Support for common mail header field generation (Message-ID, Date, Bulk-Precedence, Priority, etc.)&lt;/li&gt;
&lt;li&gt;Reusing the same SMTP connection to send multiple mails&lt;/li&gt;
&lt;li&gt;Support for attachments and inline embeds (from file system, io.Reader or embed.FS)&lt;/li&gt;
&lt;li&gt;Support for different encodings&lt;/li&gt;
&lt;li&gt;Support sending mails via a local sendmail command&lt;/li&gt;
&lt;li&gt;Message object satisfies io.WriteTo and io.Reader interfaces&lt;/li&gt;
&lt;li&gt;Support for Go's html/template and text/template (as message body, alternative part or attachment/emebed)&lt;/li&gt;
&lt;li&gt;Output to file support which allows storing mail messages as e. g. .eml files to disk to open them in a MUA&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So if you need to send mails in Go, I recommend giving it a quick look and see if it can help you accomlish your "mail tasks" easier. Feedback, bug reports, fixed and PRs are of course always welcome.&lt;/p&gt;

</description>
      <category>go</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>mail</category>
    </item>
  </channel>
</rss>
