I don't know much about go. What is "err"?
Furthermore, the sendEmail and validateEmailForm values are essentially ignored and used only for their possible error values.
Why should I wrote my program as if the thing I'm concerned primarily with is errors? Much better to encode the failure into the type. You could have, for example, some function that returns Either[Error, SendEmailAction] where SendEmailAction is a function that, when called, will perform the effect of sending an email. Now I can deal with the happy path by mapping on the right-biased Either.
Golang is a really simple language, but all the simple concepts, and the lack of OOP, forces you to think more about your code. Also you are forced to think about error conditions.
I'm still playing around with it. So i dont have a final opinion on go.
First of all, from a type-theory point of view, both Email and WebForm have the same type. (same signature).
Also from a theoretical point of view, i think a type should not have an instance if its not valid and "EmailAddress" of value "aasda" should not exists. However it is allowed in his types.
Also, I don't see how defining lots of very specific types such as FromAddress and ToAddress are really making live easier.
Something like this does the job, and is typesafe (in golang):
Tests will simply use the returnValue of sendMail to validate its inner working.