So our next major topic is how do we send email and what I want to do here is whenever someone makes
a reservation on our site, I want to send two email messages.
I want to send one to the property owner just to alert him or her that there is a new reservation.
And I want to send a confirmation email to the person who made the reservation in the first place.
And this is not terribly difficult.
So what I'm going to do is look around and I already have done I've already done so look around and
find a mail package that I can just import into my project and use one where the work is already done.
And it's maintained on a fairly regular basis.
And I found this one, which is called Go Simple Mail, which sounds ideal for my purposes.
And if you look at the district description, it's it will talk to an SMTP server, which SMTP stands
for simple mail transfer protocol.
It actually does everything we want and it's pretty easy to install and pretty easy to use.
So let's copy the part here on this page.
And I will and this is the URL, but I'll post a link to this to the course resources.
Let's copy this and install it into our project.
So back I go to buy Idy.
I open a terminal window, make sure I'm at the root level of my project.
I am and I paste that command in and it will go and get it and install it and that modifies our go mod
file and we now have it available to us.
So in order to send email we're going to need to know certain things at a bare minimum.
We're going to have to know the to address the from address the subject and the content.
So what I'm going to do now is go and create a struct, a type that will hold that kind of contact content.
So I'm going to go to my model's directory and I'll put it in models because this is a model and at
the very bottom of it, I'll create a new type type and I'll call it mail data, which is a good name.
I think it's a struct.
And it will have four members too, which is a string.
That's the email address that I'm sending to from which is a string.
Again, the email address that I'm sending from the subject of the email, which will be a string and
the content of the email.
And I'm not going to make this a string.
I could, but I want might want to put formatting in that email and that means I'm going to be sending
HTML.
So instead of making it a string, I'll make it template HTML, which is a built in type that allows
us to actually have formatting in the content that we're going to be sending out via email.
And I'll put a comment on this.
Mail data holds an email message, so I've now imported the package I want to use to send email.
And I have also set up a a model to hold the email messages that I'll be sending.
Now we need to get to the nitty gritty of how to send email.
So first thing I'm going to tell you is that I'm not going to and I could do this.
I could just create a helper function and that go construct my mail message wherever I want to send
it and then call that function and have it send it.
But I'm going to make it a little more complicated.
I'm going to do it because you need to have a little more experience working with channels in go.
And this is a perfect opportunity to use a channel to send email and to write the code necessary to
have a worker that listens for data, center that channel and perform some action when it receives it.
So I'm going to, first of all, go to my main function in command web.
I'm going to open Mango.
And in here I am going to think about what I'm going to do, what I want to do in this this this code,
either in my main function or am I run function or both, as I want to create a channel that will be
available to all parts of my application at any time.
And that channel serves one purpose.
It's going to listen for a data type of models, dot mailed mail data, that one we just created.
So how do you create a channel?
Well, we already looked at that a long time ago at the very early part of this this course.
So we know how to create a channel.
But a question is where do I put it?
I can create a channel in my main function or I can create a channel in my run function, but I want
it to be available to my entire application.
Well, why not put it in our config, in our app config?
So what I'm going to do is open up config, go and add a new member to this struct, which I will call
male channel, and it's going to be a channel of type models, dot male data.
So now once I create the channel and populate in my app config, it will be available to every part
of my application that has access to the config, which is in our case, pretty much every part of our
application.
So I've created that.
So let's go back to our main Dr..
And let's create this channel and I'll do it down in the room function and I'll do it right after my
gob register bid, so I'll create a new variable called Milchan and that will be assigned the value
of make channe models male data.
So now I have this channel and as I told you really early on in the course, we're going to need to
put a defer close on this channel because you don't want to leave channels to open all the time.
But as was the case with something else in this, and I can't remember what our database connections,
if I put my designer clothes here, it's actually going to close it as soon as this run function is
done executing.
And this only runs once at the very first time we start our application.
It's called right up here and then it closes.
So I don't want to close it here.
Instead, I will populate my app Dot Milchan with Milchan.
It's equal to Milchan.
And then up here I will just before I put starting application in my main function, I will put a defer
defer close match app Milchan.
So now I have it closed properly and this is really not enough.
So far I've created the place to hold email messages in models, dot mail data.
I've created a channel to send messages through and I've closed the channel, which will happen when
the application stops.
But I haven't actually sent any messages.
I have no means of sending a message.
So what am I going to do with this at Baleka?
Well, let's think about what we might want to do.
What I really want to do is have some part of my application that listens for that channel.
And it says, when I received some information from this channel, here's what I do with it.
So I need someplace to actually listen for this channel.
So let's do that, because in the example we did way back when we just created a channel in the main
function, sent something through a function that was beside the main function and then close the channel.
It was a one shot program that started did what it had to do and then stopped.
And in this case, we have an application that starts and it keeps running until we physically go and
stop the server.
So we need something that's going to listen to this.
So what I'm going to do is in my Web folder, I'm going to create a new file, a new go file, and it's
going to be called Send Dash Email Dutko and I will add this to my repository.
So it's part of a package main.
And what do I want to do in this?
Well, I'm going to create a function and the function is going to be called func.
Listen for mail, which is a nice descriptive title, it takes no parameters and it returns nothing.
And inside of this, what I want to do is to listen to that channel.
Well, as you may recall, the way that we get information from a channel is just to declare a variable
like M for message and make that as equal to whatever I get from the channel I want to listen to, which
in this case is apt e-mail chat.
Now, I could do that and then use this message to create and send an email message.
But it's really not helpful because again, this function needs to be called every single time I want
to send a message and that defeats the entire purposes or purpose of channels in the first place.
So what I'm going to do is just get rid of this entirely and I'm going to create something that runs
indefinitely and fires things off in the background to to happen asynchronously.
So every time I get a message I want it to send, but I don't want the application to stop running Wallace
sending that email.
So if I was to write this procedurally and just send constructive message, connect to the mail server,
send the message and keep going, there could be a delay and that delay could be three, four or five,
maybe ten seconds, because sometimes it's slow to send email.
So what I want to do instead is have that happen in the background.
And here's how I'm going to make this work.
I'm going to fire off in the background, start a go routine by using that command go.
And I'm going to fire an unnamed function or an anonymous function.
So to do that, I just say func and then open and close parentheses.
And I'm not putting any parameters in there.
I have the standard body curly braces.
And then on the closing curly brace, I'm just going to put two more parentheses.
And now I have a function that will execute in the background.
And what I want this to do is to listen all the time for incoming data.
So what I'm going to listen for, I'll just use a force, a for loop with no conditions.
And I'm going to listen to that channel.
Now, you would think I could do this message, which will be a variable I declare is equal to whatever
you get from my laptop.
Milchan.
And then I can send my message.
So let's see if this works, let's go construct a message.
So what I'm going to do now is I don't want to put this sending part right in this Falu because that
becomes a bit awkward.
I'll just get another function called Funk Send Message and now will actually pass some parameters to
this.
And in this case, this will receive a parameter which I'm going to call em, which is of type models,
e-mail data.
This doesn't return anything.
This just sends email and here's how you actually send email.
So we imported that package a little while ago and now we're going to use it.
And the first step is to tell our mail package, the one that we just imported, go simple mail what
our server is.
So I'll create a variable called server that's going to be assigned the value of mail dot new SMTP client.
OK, and this server is going to have some information associated with it, so where is your e-mail
server?
Well, in our case, it's going to be server dot host is equal to and we're just going to use localhost.
We're going to install a dummy mail server on our machines in a little while.
But we can do this part first and it's going to listen on a particular part, just like a Web server
listens on Port 80 or 443 mail servers.
Also listen on ports.
So this one has a port and the port for our dummy server that we're going to install will be 10, 25.
OK, real mail servers, USB port twenty five, Port 587 or 465 for the most case.
But right now we're going to be using a dummy e-mail server and I'll set some other parameters on this
as well.
I don't want to keep the connection to the e-mail server active all the time.
So I'll say make that false.
Only make a connection when I tell you to send email and I'll give it some sensible timeouts.
So server dot connect timeout.
I'll make that 10 seconds, 10 times time dot second.
So if you can't connect within 10 seconds, just give up and server dot send time out.
I'll make that 10 seconds as well.
Now, that's the basic information to connect to a male server.
There are other things that you will need in production.
You will need, for example, server username and server password and server dot encryption.
But we don't have that for a dummy server.
And it doesn't matter for the purposes of this course.
When you go to connect to a live server, you'll have to specify those things, but you'll have to find
out what they are first.
So for our purposes, this will give us a means of connecting to a local mail server, which I happen
to have installed and running already.
You don't don't worry about it.
You'll get there.
Now we need a client just like we have a server.
We have to have a client.
So here client and error are assigned the value of server iConnect.
And that since that throws an error, we have to look for that if there is not equal to nil.
I'll just print the error log print line error, OK?
And now we actually need to construct our email message in a format that our client understands.
And we do that using this variable M that we've got right up here.
We already have our model mailed it and that has everything we need.
So I will say email is assigned the value of mail new message which creates a new empty message.
This creates a struct and the struct is a pointer to email.
And we get that from our mail package, which I automatically import it up here, or it automatically
imported itself and called itself mail.
So we have mailed a new message and that's assigned to a variable email.
And now we just set the frame to in subject email dot from.
Not get from e-mail dot set from is set to emerg from and then I can use a dot and keep setting configurations
here, I'll add a two address and my two will be morto and all that.
A subject set subject is equal to Emerg subject.
So this actually creates an empty e-mail message.
This next line sets the from to an email address, sets the two to an email address and sets the subject
to a subject.
Now we just need to put the content of our body in there.
So email dot set body is the next one.
Now, I put this on a separate line because for right now, I don't want to manually construct an email
message.
I just want to make sure this works OK.
So this requires two parameters.
What your content type.
And we actually have some predefined constants in this mail package.
I'm going to set mine to HTML.
So mail dot text HTML.
That's the type of the content and I will put some content in here in the form of image of HTML.
Hello, comma strong world and my strong tag exclamation mark.
And now I need this.
I'm finally at the point where I can send an email message and you do it like this.
Error is equal to email dot send and you pass it to the client that you've just set up and that client
has everything it needs to know.
It has the server information, it has the client information and it has the email body or email message
actually in there.
So since I'm sending that with an email or sending that and getting an error, I should check for it.
If error is not equal to nil, then I will log print line error.
Otherwise, in this case, I'm actually going to say logged logged print line.
Email set.
OK, so there it is, I have my function already to send email, and it seems as though I could just
listen to this channel indefinitely because it never goes out of this for loop and send a message when
I get one so I can just say send a message, the function I just built and pass it MSG, which is my
message.
Shouldn't that work?
It would seem that it should.
But this listen for mail function is never actually called.
So let's go back to our main function and set that up.
And I would do that obviously somewhere up here.
I could say right after my designer clothes, after I set my DHAFIR Command to close the email channel.
When I'm done with the program, I can just say start that listening for email messages by running the
command.
Listen, for now, let's see if that works.
So I'm going to open my terminal window, clear the screen and run my program.
I'm in the right direction.
I am so let's just say run and see what happens.
Seem to work, seem to be listening.
OK, let's stop that again.
I've got my app channel all set up, let's actually try sending an email message, so I'll do it right
after listening for email.
I'm going to put it right on my main function just to make sure that things work.
So the first thing I need is a message, and that will be of type models, dot mail data.
And I will choose Phil all fields just to make it easier for for myself.
So to John at Doe Dossie from me at here, Dotcom, those have to be in the form of email addresses,
subject some subject and content and doesn't matter what content it is because I'm manually putting
that in myself.
So if I want to send to that channel now all I have to do is say app dot mail channel and pass it the
message.
So let's stop this and see what happens now on my now on my local computer, I actually have this e-mail
server you're going to be installing shortly already installed.
So let me start up that mail server and it's called Mail Hug, an unfortunate name, but a great dumb
email server.
And this is now listening for or it's listening all the time.
I just happened to open the Web interface to it.
It's listening for emails.
So let me go back to my I.D. and run this and see what happens.
So I will clear the screen.
And runit.
And off it goes and it says email sent.
So let's go back and have a look in this mail client and there is the email from me out here, NORCOM
to John at Doe Dossie.
And I can view that.
And there it is.
And there seems to be working really well.
So what this looks like I can do at this point is I can actually just anytime I want to send an email
message, construct it using this format, populate the content with the actual content that I want,
of course, and then send it to that channel and that will send email in the background.
So the last thing I have to do to make this actually functional is to go back to send Dasch mail ago
and get rid of this part.
Don't hardcourt that instead use more content and that should work.
And this has to be in the form of type string.
So it's actually template HTML.
Well, I can actually cast that back to a string, but it might be simpler just to go to our config
and say, no, this, this not our config, our models.
Dudko and change the structure from template html back to string.
I thought we had to cast it to put it in template html format.
Turns out we don't, so that's even simpler.
So now I have everything I need to be able to send email.
So let's comment this stuff out from here.
Because we're not going to be wanting to send an email every time we start the program and let's just
add a message right here, format, print line and I'll save starting mail listener.
So when we started it up, now we should get that message.
Let me stop this, clear it and make sure it all compiles and see if we get that message.
And we do everything is working perfect, so in the next lecture, we'll actually look at sending emails
around to our guest and to our property owner.