slaventius 2 years ago
parent 89e249a767
commit f791d24ad7
  1. 5
      .vscode/launch.json
  2. 8
      internal/config/config.go
  3. 34
      internal/postman.go
  4. 50
      internal/smtp/attachment.go
  5. 35
      internal/smtp/message.go
  6. 87
      internal/smtp/smtp.go

@ -11,6 +11,11 @@
"mode": "debug",
"program": "${workspaceRoot}/cmd/main.go",
"env": {
"SMTP_HOST":"smtp.mail.ru",
// "SMTP_PORT":"465",
"SMTP_PORT":"587",
"SMTP_SENDER":"test3kbot@mail.ru",
"SMTP_PASSWORD":"hwNhMgPyBzMjwCj3hFPp",
"KAFKA_PORT":"9092",
},
"args": []

@ -6,6 +6,13 @@ import (
"github.com/kelseyhightower/envconfig"
)
type smtpConfig struct {
Port int `envconfig:"SMTP_PORT"`
Host string `envconfig:"SMTP_HOST"`
Sender string `envconfig:"SMTP_SENDER"`
Password string `envconfig:"SMTP_PASSWORD"`
}
type kafkaConfig struct {
Host string `envconfig:"KAFKA_HOST"`
Port int `envconfig:"KAFKA_PORT"`
@ -13,6 +20,7 @@ type kafkaConfig struct {
// ...
type Config struct {
Smtp smtpConfig
Kafka kafkaConfig
}

@ -2,22 +2,32 @@ package postman
import (
"context"
"encoding/json"
"log"
"net"
"strconv"
"test3k/authPostman/internal/config"
smtp "test3k/authPostman/internal/smtp"
"github.com/segmentio/kafka-go"
)
type msg struct {
Code string
Email string
}
type AuthPostmanServer struct {
ctx context.Context
config *config.Config
kafkaReader *kafka.Reader
}
func NewServer(ctx context.Context, config *config.Config, topic string) *AuthPostmanServer {
return &AuthPostmanServer{
ctx: ctx,
ctx: ctx,
config: config,
kafkaReader: kafka.NewReader(kafka.ReaderConfig{
Topic: topic,
Brokers: []string{net.JoinHostPort(config.Kafka.Host, strconv.Itoa(config.Kafka.Port))},
@ -44,6 +54,26 @@ func (s *AuthPostmanServer) ReadMessage(offset int64) error {
return err
}
log.Printf("message at offset %d: %s = %s\n", m.Offset, string(m.Key), string(m.Value))
// Декодируем сообщение
amsg := msg{}
erk := json.Unmarshal(m.Value, &amsg)
if erk != nil {
return erk
}
//
message := smtp.NewMessage("Confirmation code", amsg.Code)
message.AppendRecipient(amsg.Email)
//
smtpSender := smtp.NewService(s.config.Smtp.Host, s.config.Smtp.Port, s.config.Smtp.Sender, s.config.Smtp.Password)
ers := smtpSender.Send(message)
if ers != nil {
log.Print(ers)
}
//
// log.Printf("message at offset %d: %s = %s\n", m.Offset, string(m.Key), string(m.Value))
log.Printf("send code %v to %v", amsg.Code, amsg.Email)
}
}

@ -0,0 +1,50 @@
package postman
import (
"bytes"
"encoding/base64"
"os"
)
// Вложение
type Attachment struct {
name string
contentType string
withFile bool
}
func NewAttachment(file string) Attachment {
return Attachment{
name: file,
contentType: "application/octet-stream",
withFile: true,
}
}
// Импорт файла в тело письма
func (a *Attachment) WriteFile(buffer *bytes.Buffer) error {
file, err := os.ReadFile(a.name)
if err != nil {
return err
}
//
payload := make([]byte, base64.StdEncoding.EncodedLen(len(file)))
base64.StdEncoding.Encode(payload, file)
//
buffer.WriteString("\r\n")
for index, line := 0, len(payload); index < line; index++ {
buffer.WriteByte(payload[index])
if (index+1)%76 == 0 {
_, era := buffer.WriteString("\r\n")
if era != nil {
return era
}
}
}
return nil
}

@ -0,0 +1,35 @@
package postman
// Почтовое сообщения предназначенное для отправки
type Message struct {
to []string
subject string
body string
contentType string
attachments []Attachment
}
func NewMessage(subject string, body string) Message {
return Message{
to: []string{},
subject: subject,
contentType: "text/plain;charset=utf8",
attachments: []Attachment{},
body: body,
}
}
// Пополнение списка получателей
func (m *Message) AppendRecipient(recipient string) error {
m.to = append(m.to, recipient)
return nil
}
// Пополнение списка вложений
func (m *Message) AppendAttachment(file string) error {
a := NewAttachment(file)
m.attachments = append(m.attachments, a)
return nil
}

@ -0,0 +1,87 @@
package postman
import (
"bytes"
"errors"
"net/smtp"
"strconv"
"strings"
"time"
)
// SMTP сервис
type Service struct {
user string
password string
host string
port int
}
func NewService(host string, port int, sender string, password string) *Service {
return &Service{
user: sender,
password: password,
host: host,
port: port,
}
}
// Отправка письма
func (s *Service) Send(message Message) error {
if len(message.to) < 1 {
return errors.New("empty list of recipients")
}
//
auth := smtp.PlainAuth("", s.user, s.password, s.host)
//
buffer := bytes.NewBuffer(nil)
boundary := "GoBoundary"
headery := ""
// header
header := make(map[string]string)
header["From"] = s.user
header["To"] = message.to[0]
header["Cc"] = strings.Join(message.to[1:], ";")
header["Subject"] = message.subject
header["Content-Type"] = "multipart/mixed;boundary=" + boundary
header["Mime-Version"] = "1.0"
header["Date"] = time.Now().String()
for key, value := range header {
headery += key + ":" + value + "\r\n"
}
buffer.WriteString(headery + "\r\n")
// body
body := "\r\n--" + boundary + "\r\n"
body += "Content-Type:" + message.contentType + "\r\n"
body += "\r\n" + message.body + "\r\n"
buffer.WriteString(body)
// attachments
for _, x := range message.attachments {
if x.withFile {
attachment := "\r\n--" + boundary + "\r\n"
attachment += "Content-Transfer-Encoding:base64\r\n"
attachment += "Content-Disposition:attachment\r\n"
attachment += "Content-Type:" + x.contentType + ";name=\"" + x.name + "\"\r\n"
//
buffer.WriteString(attachment)
//
x.WriteFile(buffer)
}
}
buffer.WriteString("\r\n--" + boundary + "--")
// Sending message
return smtp.SendMail(s.host+":"+strconv.Itoa(s.port), auth, s.user, message.to, buffer.Bytes())
}
Loading…
Cancel
Save