Added GO-realisation email check service
parent
94e1825419
commit
9e23e5a7c9
|
@ -0,0 +1,3 @@
|
||||||
|
.env
|
||||||
|
main
|
||||||
|
email-check
|
|
@ -0,0 +1,20 @@
|
||||||
|
FROM golang:alpine AS build
|
||||||
|
RUN apk --no-cache add gcc g++ make git
|
||||||
|
|
||||||
|
WORKDIR /go/src/app
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
RUN go get ./...
|
||||||
|
RUN GOOS=linux go build -ldflags="-s -w" -o ./bin/email-check ./email-check.go
|
||||||
|
FROM alpine:3.9
|
||||||
|
RUN apk add tzdata
|
||||||
|
#RUN apk --no-cache add ca-certificates
|
||||||
|
WORKDIR /usr/bin
|
||||||
|
COPY --from=build /go/src/app/bin /go/bin
|
||||||
|
|
||||||
|
COPY cronjobs /etc/crontabs/root
|
||||||
|
|
||||||
|
# start crond with log level 8 in foreground, output to stderr
|
||||||
|
CMD ["crond", "-f", "-d", "8"]
|
||||||
|
|
||||||
|
#ENTRYPOINT /go/bin/email-check
|
|
@ -0,0 +1,131 @@
|
||||||
|
# Email Monitoring
|
||||||
|
|
||||||
|
"Сервис" проверки отправки и получения почты с возможностью мониторинга в Zabbix. Также можно просто отправлять любые сообщения с целью автоматизации чего-нибудь.
|
||||||
|
|
||||||
|
Пароли от учетных записей почты сервис может брать из Hashicorp Vault.
|
||||||
|
|
||||||
|
Программу можно запускать как в консоли так и в docker-контейнере.
|
||||||
|
|
||||||
|
# Режимы работы
|
||||||
|
|
||||||
|
|
||||||
|
# использование
|
||||||
|
|
||||||
|
Для работы используются переменные окружения (либо соответствующие им ключи (опции) командной строки), при указании параметров с командной строки , переменные окружения будут проигнорированы:
|
||||||
|
|
||||||
|
- IMAP_SERVER=imap.google.com
|
||||||
|
- IMAP_PORT=143
|
||||||
|
- IMAP_USER=some@gmail.com
|
||||||
|
- IMAP_PASSWORD=12345
|
||||||
|
- MAIL_FROM=some@localmaildomain.ru
|
||||||
|
- MAIL_MESSAGE="Message body"
|
||||||
|
- MAIL_SUBJECT="Test email subject"
|
||||||
|
- MAIL_TO=""some@gmail.com
|
||||||
|
- SMTP_SERVER=smtp.localmaildomain.ru
|
||||||
|
- SMTP_PORT=25
|
||||||
|
- SMTP_USER=some@localmaildomain.ru
|
||||||
|
- SMTP_PASSWORD=123456
|
||||||
|
- VAULT_ADDRESS=https://you.vault.address
|
||||||
|
- VAULT_TOKEN="You vault token"
|
||||||
|
- ZABBIX_SERVER=https://zabbix2
|
||||||
|
- ZABBIX_HOST=mail.localmaildomain.ru
|
||||||
|
- ZABBIX_USERNAME=zabbix_user
|
||||||
|
- ZABBIX_PASSWORD=somepass
|
||||||
|
|
||||||
|
Для отправки сообщения следует указать опцию "-send" и задать все остальные параметры (адреса, пользователей и так далее), для проверки получения сообщения надо указать "-recieve". Если указать обе опции то будет протестирована отправка и получение одного сообщения.
|
||||||
|
Если Тема (mail-subject) и Сообщение (mail-message) не указаны то будет сгенерирован уникальный код, который будет вставлен в сообщение.
|
||||||
|
|
||||||
|
При указании адреса vault и токена с командной строки или через переменные окружения, пароли будут взяты оттуда. В качестве ключа используются значения SMTP_USER (-smtp-user), IMAP_USER (-imap-user), ZABBIX_USER (-zabbix-api-user). Если секреты для почтовых адресов и пароли от заббикса (API) хрянятся в разных разделах, то путь к хранилищу VAULT можно построить указав отдельные пути при помощи опций "-vault-email-secret-path" и "-vault-zabbix-secret-path". Т.е.:
|
||||||
|
|
||||||
|
Если указать значения параметров:
|
||||||
|
```
|
||||||
|
-vault-address="https://vault:8200/v1/secret/data/"
|
||||||
|
-vault-email-secret-path="email"
|
||||||
|
-vault-zabbix-secret-path="zabbix/helpers"
|
||||||
|
```
|
||||||
|
или
|
||||||
|
|
||||||
|
```
|
||||||
|
-vault-address="https://vault:8200"
|
||||||
|
-vault-email-secret-path="/v1/secret/data/email"
|
||||||
|
-vault-zabbix-secret-path="/v1/secret/data/zabbix/helpers"
|
||||||
|
```
|
||||||
|
|
||||||
|
То, получим полный путь "https://vault:8200/v1/secret/data/email" или https://vault:8200/v1/secret/data/zabbix/helpers".
|
||||||
|
|
||||||
|
Для отправки результатов проверки в zabbix можно использовать как Zabbix API (опция "-zabbix-api") так и zabbix-sender (опция "-zabbix-sender"). При указании одного из этих вариантов требуется также указывать параметры работы с заббикс (адрес сервера, узел, пользователя -zabbix-api-user и пароль -zabbix-api-password (в случае АПИ)). Но предварительно следует настроить узел в заббикс и подключить к нему приложенный шаблон (шаблон настроен на использование zabbix-sender).
|
||||||
|
|
||||||
|
## Пример команды
|
||||||
|
|
||||||
|
Отправка сообщения через локальный SMTP сервер с авторизацией (пароли будут взяты из хрфнилища секретов Vault), и проверка получения этого сообщения в учетной записи gmail по imap:
|
||||||
|
|
||||||
|
```
|
||||||
|
email-check -mail-from "some@localmaildomain.ru" -mail-to "some@gmail.com" \
|
||||||
|
-smtp-user="some@localmaildomain.ru" -smtp-server="smtp.localmaildomain.ru" -smtp-port="25" \
|
||||||
|
-imap-port="993" -vault-address="https://vault:8200/v1/secret/data/email" \
|
||||||
|
-imap-user="some@gmail.com" -imap-server="imap.google.com" -send -recieve -delay 20
|
||||||
|
```
|
||||||
|
|
||||||
|
Опция "-delay" устанавливает задержку между отправкой и получением (чтением) сообщения и по умолчанию равна 10 секунд. Это необходимо для того, чтобы сообщение успело пройти все фильтры и проверки почтовой системы.
|
||||||
|
|
||||||
|
# Краткая помощь по программе
|
||||||
|
|
||||||
|
Опции командной строки:
|
||||||
|
|
||||||
|
```
|
||||||
|
-delay int
|
||||||
|
Pause is required between operations (default 10)
|
||||||
|
-direction string
|
||||||
|
Direction of email checking. Must be an: 'local', 'incoming', 'outgoing'. (default "local")
|
||||||
|
-imap-password string
|
||||||
|
IMAP user password (IMAP_PASSWORD)
|
||||||
|
-imap-port string
|
||||||
|
IMAP server port (IMAP_PORT) (default "993")
|
||||||
|
-imap-server string
|
||||||
|
IMAP server address (IMAP_SERVER)
|
||||||
|
-imap-user string
|
||||||
|
IMAP user (IMAP_USER)
|
||||||
|
-mail-from string
|
||||||
|
Mail sender address 'From' (MAIL_FROM)
|
||||||
|
-mail-message string
|
||||||
|
Mail message body (MAIL_MESSAGE)
|
||||||
|
-mail-subject string
|
||||||
|
Mail message subject (MAIL_SUBJECT)
|
||||||
|
-mail-to string
|
||||||
|
Mail receiver address 'From' (MAIL_TO)
|
||||||
|
-receive
|
||||||
|
receive message is ON
|
||||||
|
-send
|
||||||
|
Sending message is ON
|
||||||
|
-smtp-password string
|
||||||
|
SMTP user password (SMTP_PASSWORD)
|
||||||
|
-smtp-port string
|
||||||
|
SMTP server port (SMTP_PORT) (default "25")
|
||||||
|
-smtp-server string
|
||||||
|
SMTP server address (SMTP_SERVER)
|
||||||
|
-smtp-user string
|
||||||
|
SMTP user (SMTP_USER)
|
||||||
|
-use-zabbix-sender
|
||||||
|
Send metrics or discovery data into zabbix via zabbix-sender
|
||||||
|
-vault-address string
|
||||||
|
Hashicorp (c) vault address (VAULT_ADDRESS)
|
||||||
|
-vault-email-secret-path string
|
||||||
|
Path to Vault email secret, where 'full Vault path' = 'vault-address' + 'vault-email-secret-path'
|
||||||
|
-vault-token string
|
||||||
|
Vault access token (VAULT_TOKEN)
|
||||||
|
-vault-zabbix-secret-path string
|
||||||
|
Path to Vault zabbix secret, where 'full Vault path' = 'vault-address' + 'vault-zabbix-secret-path'
|
||||||
|
-zabbix-api
|
||||||
|
Send metrics or discovery data into zabbix via Zabbix API (not implemented yet)
|
||||||
|
-zabbix-api-password string
|
||||||
|
Zabbix server API password
|
||||||
|
-zabbix-api-user string
|
||||||
|
Zabbix server API user
|
||||||
|
-zabbix-host string
|
||||||
|
Zabbix monitoring host name
|
||||||
|
-zabbix-port int
|
||||||
|
Zabbix server port (default 10051)
|
||||||
|
-zabbix-server string
|
||||||
|
Zabbix server address
|
||||||
|
|
||||||
|
```
|
|
@ -0,0 +1,5 @@
|
||||||
|
*/10 * * * * /go/bin/email-check -mail-to "${EXT_RECEIVER_EMAIL}" -mail-from "${SENDER_EMAIL}" -imap-user="${EXT_RECEIVER_EMAIL}" -imap-server="${EXT_IMAP_SERVER}" -smtp-user="${SENDER_EMAIL}" -smtp-server="${MAIL_SERVER}" -send -receive -delay 10 -direction outgoing -use-zabbix-sender -zabbix-host="${MAIL_SERVER}" -vault-email-secret-path="/v1/secret-inf/data/email" >> /var/log/email-check-out.log 2>&1
|
||||||
|
|
||||||
|
*/10 * * * * /go/bin/email-check -mail-to "${RECEIVER_EMAIL}" -mail-from "${EXT_SENDER_EMAIL}" -imap-user="${RECEIVER_EMAIL}" -imap-server="${MAIL_SERVER}" -smtp-user="${EXT_SENDER_EMAIL}" -smtp-server="${EXT_SMTP_SERVER}" -send -receive -delay 10 -direction incoming -use-zabbix-sender -zabbix-host="${MAIL_SERVER}" -vault-email-secret-path="/v1/secret-inf/data/email" >> /var/log/email-check-in.log 2>&1
|
||||||
|
|
||||||
|
*/10 * * * * /go/bin/email-check -mail-to "${RECEIVER_EMAIL}" -mail-from "${SENDER_EMAIL}" -imap-user="${RECEIVER_EMAIL}" -imap-server="${MAIL_SERVER}" -smtp-user="${SENDER_EMAIL}" -smtp-server="${MAIL_SERVER}" -send -receive -direction local -use-zabbix-sender -zabbix-host="${MAIL_SERVER}" -vault-email-secret-path="/v1/secret-inf/data/email" >> /var/log/email-check-local.log 2>&1
|
|
@ -0,0 +1,9 @@
|
||||||
|
version: '3'
|
||||||
|
|
||||||
|
services:
|
||||||
|
check_email:
|
||||||
|
image: check-email-delivery:latest
|
||||||
|
env_file: .env
|
||||||
|
restart: always
|
||||||
|
build:
|
||||||
|
context: .
|
|
@ -0,0 +1,585 @@
|
||||||
|
// ------------------------------------------------------
|
||||||
|
// Email sender and receiver for checking mail transport
|
||||||
|
// Author: Sergey Kalinin, 2022
|
||||||
|
//-------------------------------------------------------
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"net/smtp"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/adubkov/go-zabbix"
|
||||||
|
"github.com/emersion/go-imap"
|
||||||
|
"github.com/emersion/go-imap/client"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SmtpSession struct {
|
||||||
|
smtpUser string
|
||||||
|
smtpPassword string
|
||||||
|
smtpServer string
|
||||||
|
smtpPort string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ImapSession struct {
|
||||||
|
imapPassword string
|
||||||
|
imapServer string
|
||||||
|
imapUser string
|
||||||
|
imapPort string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ZabbixSession struct {
|
||||||
|
zabbixUser string
|
||||||
|
zabbixPassword string
|
||||||
|
zabbixServer string
|
||||||
|
zabbixPort int
|
||||||
|
zabbixHost string
|
||||||
|
}
|
||||||
|
|
||||||
|
type MailMessage struct {
|
||||||
|
mailFrom string
|
||||||
|
mailTo string
|
||||||
|
mailSubject string
|
||||||
|
mailMessage string
|
||||||
|
messageUUID string
|
||||||
|
}
|
||||||
|
|
||||||
|
type loginAuth struct {
|
||||||
|
username, password string
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoginAuth(username, password string) smtp.Auth {
|
||||||
|
return &loginAuth{username, password}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *loginAuth) Start(server *smtp.ServerInfo) (string, []byte, error) {
|
||||||
|
return "LOGIN", []byte(a.username), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *loginAuth) Next(fromServer []byte, more bool) ([]byte, error) {
|
||||||
|
if more {
|
||||||
|
switch string(fromServer) {
|
||||||
|
case "Username:":
|
||||||
|
return []byte(a.username), nil
|
||||||
|
case "Password:":
|
||||||
|
return []byte(a.password), nil
|
||||||
|
default:
|
||||||
|
return nil, errors.New("Unknown from server")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func sendEmail(smtpSession *SmtpSession, message *MailMessage) bool {
|
||||||
|
|
||||||
|
// Receiver email address.
|
||||||
|
to := []string{
|
||||||
|
message.mailTo,
|
||||||
|
}
|
||||||
|
|
||||||
|
serverName := smtpSession.smtpServer + ":" + smtpSession.smtpPort
|
||||||
|
// fmt.Println(serverName, smtpSession.smtpUser, smtpSession.smtpPassword)
|
||||||
|
|
||||||
|
conn, err := net.Dial("tcp", serverName)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
c, err := smtp.NewClient(conn, smtpSession.smtpServer)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tlsconfig := &tls.Config{
|
||||||
|
ServerName: smtpSession.smtpServer,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = c.StartTLS(tlsconfig); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
auth := LoginAuth(smtpSession.smtpUser, smtpSession.smtpPassword)
|
||||||
|
|
||||||
|
if err = c.Auth(auth); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := []byte("From: " + message.mailFrom + "\r\n" +
|
||||||
|
"To: " + message.mailTo + "\r\n" +
|
||||||
|
"Subject: " + message.mailSubject + "\r\n\r\n" +
|
||||||
|
message.mailMessage + "\r\n")
|
||||||
|
|
||||||
|
// Sending email.
|
||||||
|
err = smtp.SendMail(serverName, auth, message.mailFrom, to, msg)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// fmt.Println("Email Sent!")
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
log.Println("Email", message.messageUUID, "from", message.mailFrom, "sent successfully via", smtpSession.smtpServer)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var httpClient = &http.Client{
|
||||||
|
Timeout: 10 * time.Second,
|
||||||
|
}
|
||||||
|
|
||||||
|
func genMessageUID() string {
|
||||||
|
id := uuid.New().String()
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
|
func getVaultData(vaultAddr string, vaultToken string, vaultSecretName string) string {
|
||||||
|
|
||||||
|
customTransport := &(*http.DefaultTransport.(*http.Transport))
|
||||||
|
customTransport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
|
||||||
|
|
||||||
|
client := &http.Client{Transport: customTransport}
|
||||||
|
// client := &http.Client{}
|
||||||
|
|
||||||
|
req, _ := http.NewRequest("GET", vaultAddr, nil)
|
||||||
|
req.Header.Add("Accept", "application/json")
|
||||||
|
req.Header.Add("X-Vault-Token", vaultToken)
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Errored when sending request to the Vault server")
|
||||||
|
}
|
||||||
|
|
||||||
|
var result map[string]interface{}
|
||||||
|
json.NewDecoder(resp.Body).Decode(&result)
|
||||||
|
secret := result["data"].(map[string]interface{})["data"].(map[string]interface{})[vaultSecretName]
|
||||||
|
|
||||||
|
return fmt.Sprint(secret)
|
||||||
|
}
|
||||||
|
|
||||||
|
func zabbixSender(zabbixSession *ZabbixSession, zabbixItem string, zabbixItemValue string) bool {
|
||||||
|
var (
|
||||||
|
metrics []*zabbix.Metric
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
metrics = append(metrics, zabbix.NewMetric(zabbixSession.zabbixHost, zabbixItem, zabbixItemValue, time.Now().Unix()))
|
||||||
|
// metrics = append(metrics, zabbix.NewMetric(zabbixSession.zabbixHost, "status", "OK"))
|
||||||
|
|
||||||
|
// Create instance of Packet class
|
||||||
|
packet := zabbix.NewPacket(metrics)
|
||||||
|
// fmt.Println(zabbix_host, metric_name, metric_value, metrics)
|
||||||
|
// Send packet to zabbix
|
||||||
|
z := zabbix.NewSender(zabbixSession.zabbixServer, zabbixSession.zabbixPort)
|
||||||
|
res, err := z.Send(packet)
|
||||||
|
log.Println(zabbixSession.zabbixServer, zabbixSession.zabbixPort, zabbixSession.zabbixHost, zabbixItem, zabbixItemValue, metrics, zabbixSession)
|
||||||
|
log.Println("Result", string(res))
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Sending to zabbix should have failed:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func receiveEmail(imapSession *ImapSession, message *MailMessage) bool {
|
||||||
|
|
||||||
|
serverName := imapSession.imapServer + ":" + imapSession.imapPort
|
||||||
|
|
||||||
|
log.Println("Connecting to server", serverName, "...")
|
||||||
|
|
||||||
|
// Connect to server
|
||||||
|
c, err := client.DialTLS(serverName, nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
log.Println("Connected")
|
||||||
|
log.Println("Trying to logged in to imap with username", imapSession.imapUser, "...")
|
||||||
|
// Don't forget to logout
|
||||||
|
defer c.Logout()
|
||||||
|
|
||||||
|
// Login
|
||||||
|
if err := c.Login(imapSession.imapUser, imapSession.imapPassword); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
log.Println(imapSession.imapUser, "logged in")
|
||||||
|
|
||||||
|
// Select INBOX
|
||||||
|
_, err = c.Select("INBOX", false)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
log.Println("Select the INBOX:")
|
||||||
|
|
||||||
|
// Get the last 4 messages
|
||||||
|
// from := uint32(1)
|
||||||
|
// to := mbox.Messages
|
||||||
|
// if mbox.Messages > 10 {
|
||||||
|
// // We're using unsigned integers here, only subtract if the result is > 0
|
||||||
|
// from = mbox.Messages - 10
|
||||||
|
// }
|
||||||
|
// seqset := new(imap.SeqSet)
|
||||||
|
// seqset.AddRange(from, to)
|
||||||
|
|
||||||
|
// messages := make(chan *imap.Message, 10)
|
||||||
|
// done := make(chan error, 1)
|
||||||
|
|
||||||
|
// go func() {
|
||||||
|
// done <- c.Fetch(seqset, []imap.FetchItem{imap.FetchEnvelope, imap.FetchUid}, messages)
|
||||||
|
// }()
|
||||||
|
// // var uid uint32
|
||||||
|
// log.Println("Search message with subject", message.mailSubject, "in last messages:")
|
||||||
|
// for msg := range messages {
|
||||||
|
// log.Println(msg.Uid)
|
||||||
|
// if msg.Envelope.Subject == message.mailSubject {
|
||||||
|
// log.Println("Message was found:", msg.Envelope.Subject, msg.Envelope.MessageId, msg.Uid)
|
||||||
|
// // uid = msg.Uid
|
||||||
|
// // item := imap.FormatFlagsOp(imap.AddFlags, true)
|
||||||
|
// // flags := []interface{}{imap.DeletedFlag}
|
||||||
|
// // if err := c.Store(seqset, item, flags, nil); err != nil {
|
||||||
|
// // log.Fatal(err)
|
||||||
|
// // } else {
|
||||||
|
// // log.Println("Message with UID", mbox.Messages, "was marked for deletion")
|
||||||
|
// // }
|
||||||
|
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if err := <-done; err != nil {
|
||||||
|
// log.Fatal(err)
|
||||||
|
// return false
|
||||||
|
// }
|
||||||
|
|
||||||
|
// -----------------------
|
||||||
|
// We will delete the last message
|
||||||
|
// if mbox.Messages == 0 {
|
||||||
|
// log.Fatal("No message in mailbox")
|
||||||
|
// }
|
||||||
|
// seqset.Clear()
|
||||||
|
// seqSet := new(imap.SeqSet)
|
||||||
|
|
||||||
|
// seqSet.AddNum(uid)
|
||||||
|
|
||||||
|
// // First mark the message as deleted
|
||||||
|
// item := imap.FormatFlagsOp(imap.AddFlags, true)
|
||||||
|
// flags := []interface{}{imap.DeletedFlag}
|
||||||
|
// if err := c.Store(seqSet, item, flags, nil); err != nil {
|
||||||
|
// log.Fatal(err)
|
||||||
|
// } else {
|
||||||
|
// log.Println("Last", mbox.Messages, "messages was marked for deletion")
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Then delete it
|
||||||
|
// if err := c.Expunge(nil); err != nil {
|
||||||
|
// log.Fatal(err)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// log.Println("Last messages has been deleted")
|
||||||
|
|
||||||
|
log.Println("Search message with subject", message.mailSubject, "in last messages...")
|
||||||
|
|
||||||
|
criteria := imap.NewSearchCriteria()
|
||||||
|
|
||||||
|
criteria.Text = []string{message.mailSubject}
|
||||||
|
ids, err := c.Search(criteria)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
log.Println("Total messages :", ids)
|
||||||
|
|
||||||
|
if len(ids) > 0 {
|
||||||
|
seqset := new(imap.SeqSet)
|
||||||
|
seqset.AddNum(ids...)
|
||||||
|
|
||||||
|
messages := make(chan *imap.Message, 10)
|
||||||
|
done := make(chan error, 1)
|
||||||
|
go func() {
|
||||||
|
done <- c.Fetch(seqset, []imap.FetchItem{imap.FetchEnvelope}, messages)
|
||||||
|
}()
|
||||||
|
|
||||||
|
// log.Println("Unseen messages:")
|
||||||
|
for msg := range messages {
|
||||||
|
log.Println("Message was found:", msg.Envelope.Subject, msg.Envelope.MessageId, msg.Uid)
|
||||||
|
// log.Println("* " + msg.Envelope.Subject)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := <-done; err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
item := imap.FormatFlagsOp(imap.AddFlags, true)
|
||||||
|
flags := []interface{}{imap.DeletedFlag}
|
||||||
|
if err := c.Store(seqset, item, flags, nil); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
log.Println("The message with subject", message.mailSubject, "was marked for deletion")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then delete it
|
||||||
|
log.Println("Delete marked messages...")
|
||||||
|
if err := c.Expunge(nil); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
} else {
|
||||||
|
log.Println("All marked messages was deleted")
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("Done!")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var (
|
||||||
|
vaultAddress string
|
||||||
|
vaultToken string
|
||||||
|
vaultEmailSecretPath string
|
||||||
|
vaultZabbixSecretPath string
|
||||||
|
vaultPath string
|
||||||
|
message MailMessage
|
||||||
|
smtpSession SmtpSession
|
||||||
|
imapSession ImapSession
|
||||||
|
zabbixSession ZabbixSession
|
||||||
|
sendMessage bool
|
||||||
|
receiveMessage bool
|
||||||
|
operationDelay int
|
||||||
|
useZabbixSender bool
|
||||||
|
zabbixApi bool
|
||||||
|
err error
|
||||||
|
msgSendResult bool
|
||||||
|
msgReceiveResult bool
|
||||||
|
direction string
|
||||||
|
)
|
||||||
|
|
||||||
|
// Genarate uniq ID
|
||||||
|
message.messageUUID = genMessageUID()
|
||||||
|
|
||||||
|
// ----------------------------------------------------------
|
||||||
|
// Read command line options and and settins the variables
|
||||||
|
|
||||||
|
flag.StringVar(&message.mailFrom, "mail-from", "", "Mail sender address 'From' (MAIL_FROM)")
|
||||||
|
flag.StringVar(&message.mailTo, "mail-to", "", "Mail receiver address 'From' (MAIL_TO)")
|
||||||
|
flag.StringVar(&message.mailSubject, "mail-subject", "", "Mail message subject (MAIL_SUBJECT)")
|
||||||
|
flag.StringVar(&message.mailMessage, "mail-message", "", "Mail message body (MAIL_MESSAGE)")
|
||||||
|
flag.StringVar(&smtpSession.smtpServer, "smtp-server", "", "SMTP server address (SMTP_SERVER)")
|
||||||
|
flag.StringVar(&smtpSession.smtpPort, "smtp-port", "587", "SMTP server port (SMTP_PORT)")
|
||||||
|
flag.StringVar(&smtpSession.smtpUser, "smtp-user", "", "SMTP user (SMTP_USER)")
|
||||||
|
flag.StringVar(&smtpSession.smtpPassword, "smtp-password", "", "SMTP user password (SMTP_PASSWORD)")
|
||||||
|
flag.StringVar(&imapSession.imapServer, "imap-server", "", "IMAP server address (IMAP_SERVER)")
|
||||||
|
flag.StringVar(&imapSession.imapPort, "imap-port", "993", "IMAP server port (IMAP_PORT)")
|
||||||
|
flag.StringVar(&imapSession.imapUser, "imap-user", "", "IMAP user (IMAP_USER)")
|
||||||
|
flag.StringVar(&imapSession.imapPassword, "imap-password", "", "IMAP user password (IMAP_PASSWORD)")
|
||||||
|
flag.StringVar(&vaultAddress, "vault-address", "", "Hashicorp (c) vault address (VAULT_ADDRESS)")
|
||||||
|
flag.StringVar(&vaultToken, "vault-token", "", "Vault access token (VAULT_TOKEN)")
|
||||||
|
flag.StringVar(&vaultEmailSecretPath, "vault-email-secret-path", "", "Path to Vault email secret, where 'full Vault path' = 'vault-address' + 'vault-email-secret-path'")
|
||||||
|
flag.StringVar(&vaultZabbixSecretPath, "vault-zabbix-secret-path", "", "Path to Vault zabbix secret, where 'full Vault path' = 'vault-address' + 'vault-zabbix-secret-path'")
|
||||||
|
flag.BoolVar(&sendMessage, "send", false, "Sending message is ON")
|
||||||
|
flag.BoolVar(&receiveMessage, "receive", false, "receive message is ON")
|
||||||
|
flag.IntVar(&operationDelay, "delay", 5, "Pause is required between operations")
|
||||||
|
flag.BoolVar(&useZabbixSender, "use-zabbix-sender", false, "Send metrics or discovery data into zabbix via zabbix-sender")
|
||||||
|
flag.BoolVar(&zabbixApi, "zabbix-api", false, "Send metrics or discovery data into zabbix via Zabbix API (not implemented yet)")
|
||||||
|
flag.StringVar(&zabbixSession.zabbixServer, "zabbix-server", "", "Zabbix server address (ZABBIX_SERVER)")
|
||||||
|
flag.IntVar(&zabbixSession.zabbixPort, "zabbix-port", 10051, "Zabbix server port (ZABBIX_PORT)")
|
||||||
|
flag.StringVar(&zabbixSession.zabbixUser, "zabbix-api-user", "", "Zabbix server API user (ZABBIX_USER)")
|
||||||
|
flag.StringVar(&zabbixSession.zabbixPassword, "zabbix-api-password", "", "Zabbix server API password (ZABBIX_PASSWORD)")
|
||||||
|
flag.StringVar(&zabbixSession.zabbixHost, "zabbix-host", "", "Zabbix monitoring host name")
|
||||||
|
flag.StringVar(&direction, "direction", "local", "Direction of email checking. Must be an: 'local', 'incoming', 'outgoing'.")
|
||||||
|
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
if os.Getenv("VAULT_ADDRESS") != "" {
|
||||||
|
vaultAddress = os.Getenv("VAULT_ADDRESS")
|
||||||
|
}
|
||||||
|
|
||||||
|
if vaultAddress != "" && vaultToken == "" && os.Getenv("VAULT_TOKEN") == "" {
|
||||||
|
fmt.Println("If You setting VAULT_ADDRES, You must sure environment variables `VAULT_TOKEN`, or used with '-vault-token' argument")
|
||||||
|
os.Exit(1)
|
||||||
|
} else if vaultToken == "" && os.Getenv("VAULT_TOKEN") != "" {
|
||||||
|
vaultToken = os.Getenv("VAULT_TOKEN")
|
||||||
|
}
|
||||||
|
|
||||||
|
if message.mailFrom == "" && os.Getenv("MAIL_FROM") == "" {
|
||||||
|
fmt.Println("Make sure environment variables `MAIL_FROM`, or used with '-mail-from' argument")
|
||||||
|
os.Exit(1)
|
||||||
|
} else if message.mailFrom == "" && os.Getenv("MAIL_FROM") != "" {
|
||||||
|
message.mailFrom = os.Getenv("MAIL_FROM")
|
||||||
|
}
|
||||||
|
|
||||||
|
if message.mailTo == "" && os.Getenv("MAIL_TO") == "" {
|
||||||
|
fmt.Println("Make sure environment variables `MAIL_TO`, or used with '-mail-to' argument")
|
||||||
|
os.Exit(1)
|
||||||
|
} else if message.mailTo == "" && os.Getenv("MAIL_TO") != "" {
|
||||||
|
message.mailTo = os.Getenv("MAIL_TO")
|
||||||
|
}
|
||||||
|
|
||||||
|
if message.mailSubject == "" && os.Getenv("MAIL_SUBJECT") == "" {
|
||||||
|
message.mailSubject = message.messageUUID
|
||||||
|
// fmt.Println("Make sure environment variables `MAIL_SUBJECT`, or used with '-mail-subject' argument")
|
||||||
|
// os.Exit(1)
|
||||||
|
} else if message.mailSubject == "" && os.Getenv("MAIL_SUBJECT") != "" {
|
||||||
|
message.mailFrom = os.Getenv("MAIL_SUBJECT")
|
||||||
|
}
|
||||||
|
|
||||||
|
if message.mailMessage == "" && os.Getenv("MAIL_MESSAGE") == "" {
|
||||||
|
message.mailMessage = message.messageUUID
|
||||||
|
// fmt.Println("Make sure environment variables `MAIL_MESSAGE`, or used with '-mail-message' argument")
|
||||||
|
// os.Exit(1)
|
||||||
|
} else if message.mailMessage == "" && os.Getenv("MAIL_MESSAGE") != "" {
|
||||||
|
message.mailMessage = os.Getenv("MAIL_MESSAGE")
|
||||||
|
}
|
||||||
|
|
||||||
|
if smtpSession.smtpUser == "" && os.Getenv("SMTP_USER") == "" {
|
||||||
|
fmt.Println("Make sure environment variables `SMTP_USER`, or used with '-smtp-user' argument")
|
||||||
|
os.Exit(1)
|
||||||
|
} else if smtpSession.smtpUser == "" && os.Getenv("SMTP_USER") != "" {
|
||||||
|
smtpSession.smtpServer = os.Getenv("SMTP_USER")
|
||||||
|
}
|
||||||
|
|
||||||
|
if smtpSession.smtpPassword == "" && os.Getenv("SMTP_PASSWORD") == "" && vaultAddress == "" {
|
||||||
|
fmt.Println("Make sure environment variables `SMTP_PASSWORD`, or used with '-smtp-password' argument")
|
||||||
|
os.Exit(1)
|
||||||
|
} else if smtpSession.smtpPassword == "" && os.Getenv("SMTP_PASSWORD") != "" {
|
||||||
|
smtpSession.smtpPassword = os.Getenv("SMTP_PASSWORD")
|
||||||
|
} else if vaultAddress != "" && smtpSession.smtpUser != "" && smtpSession.smtpPassword == "" {
|
||||||
|
vaultPath = vaultAddress + vaultEmailSecretPath
|
||||||
|
smtpSession.smtpPassword = getVaultData(vaultPath, vaultToken, smtpSession.smtpUser)
|
||||||
|
// fmt.Println(smtpUser, smtpPassword)
|
||||||
|
}
|
||||||
|
|
||||||
|
if smtpSession.smtpServer == "" && os.Getenv("SMTP_SERVER") == "" {
|
||||||
|
fmt.Println("Make sure environment variables `SMTP_SERVER`, or used with '-smtp-server' argument")
|
||||||
|
os.Exit(1)
|
||||||
|
} else if smtpSession.smtpServer == "" && os.Getenv("SMTP_SERVER") != "" {
|
||||||
|
smtpSession.smtpServer = os.Getenv("SMTP_SERVER")
|
||||||
|
}
|
||||||
|
|
||||||
|
if imapSession.imapUser == "" && os.Getenv("IMAP_USER") == "" {
|
||||||
|
fmt.Println("Make sure environment variables `IMAP_USER`, or used with '-imap-user' argument")
|
||||||
|
os.Exit(1)
|
||||||
|
} else if imapSession.imapUser == "" && os.Getenv("IMAP_USER") != "" {
|
||||||
|
imapSession.imapServer = os.Getenv("IMAP_USER")
|
||||||
|
}
|
||||||
|
|
||||||
|
if imapSession.imapPassword == "" && os.Getenv("IMAP_PASSWORD") == "" && vaultAddress == "" {
|
||||||
|
fmt.Println("Make sure environment variables `IMAP_PASSWORD`, or used with '-imap-password' argument")
|
||||||
|
os.Exit(1)
|
||||||
|
} else if imapSession.imapUser == "" && os.Getenv("IMAP_PASSWORD") != "" {
|
||||||
|
imapSession.imapPassword = os.Getenv("IMAP_PASSWORD")
|
||||||
|
} else if vaultAddress != "" && imapSession.imapUser != "" && imapSession.imapPassword == "" {
|
||||||
|
// secret := append("")
|
||||||
|
vaultPath = vaultAddress + vaultEmailSecretPath
|
||||||
|
imapSession.imapPassword = getVaultData(vaultPath, vaultToken, imapSession.imapUser)
|
||||||
|
// fmt.Println(imapUser, imapPassword)
|
||||||
|
}
|
||||||
|
|
||||||
|
if imapSession.imapServer == "" && os.Getenv("IMAP_SERVER") == "" {
|
||||||
|
fmt.Println("Make sure environment variables `IMAP_SERVER`, or used with '-imap-server' argument")
|
||||||
|
os.Exit(1)
|
||||||
|
} else if imapSession.imapServer == "" && os.Getenv("IMAP_SERVER") != "" {
|
||||||
|
imapSession.imapServer = os.Getenv("IMAP_SERVER")
|
||||||
|
}
|
||||||
|
|
||||||
|
if zabbixApi || useZabbixSender {
|
||||||
|
if zabbixSession.zabbixServer == "" && os.Getenv("ZABBIX_SERVER") == "" {
|
||||||
|
fmt.Println("Make sure environment variables `ZABBIX_SERVER`, or used with '-zabbix-server' argument")
|
||||||
|
os.Exit(1)
|
||||||
|
} else if zabbixSession.zabbixServer == "" && os.Getenv("ZABBIX_SERVER") != "" {
|
||||||
|
zabbixSession.zabbixServer = os.Getenv("ZABBIX_SERVER")
|
||||||
|
}
|
||||||
|
|
||||||
|
if os.Getenv("ZABBIX_PORT") != "" {
|
||||||
|
fmt.Println("Make sure environment variables `ZABBIX_PORT`, or used with '-zabbix-port' argument")
|
||||||
|
os.Exit(1)
|
||||||
|
if zabbixSession.zabbixPort, err = strconv.Atoi(os.Getenv("ZABBIX_PORT")); err != nil {
|
||||||
|
log.Println(zabbixSession.zabbixPort, "Zabbix port value error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if zabbixSession.zabbixHost == "" && os.Getenv("ZABBIX_HOST") == "" {
|
||||||
|
fmt.Println("Make sure environment variables `ZABBIX_HOST`, or used with '-zabbix-host' argument")
|
||||||
|
os.Exit(1)
|
||||||
|
} else if zabbixSession.zabbixHost == "" && os.Getenv("ZABBIX_HOST") != "" {
|
||||||
|
zabbixSession.zabbixHost = os.Getenv("ZABBIX_HOST")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if zabbixApi {
|
||||||
|
if zabbixSession.zabbixUser == "" && os.Getenv("ZABBIX_USER") == "" {
|
||||||
|
fmt.Println("Make sure environment variables `ZABBIX_USER`, or used with '-zabbix-api-user' argument")
|
||||||
|
os.Exit(1)
|
||||||
|
} else if zabbixSession.zabbixUser == "" && os.Getenv("ZABBIX_USER") != "" {
|
||||||
|
zabbixSession.zabbixUser = os.Getenv("ZABBIX_USER")
|
||||||
|
}
|
||||||
|
|
||||||
|
if zabbixSession.zabbixPassword == "" && os.Getenv("ZABBIX_PASSWORD") == "" {
|
||||||
|
fmt.Println("Make sure environment variables `ZABBIX_PASSWORD`, or used with '-zabbix-api-password' argument")
|
||||||
|
os.Exit(1)
|
||||||
|
} else if vaultAddress != "" && zabbixSession.zabbixUser != "" && zabbixSession.zabbixPassword == "" {
|
||||||
|
// secret := append("")
|
||||||
|
vaultPath = vaultAddress + vaultZabbixSecretPath
|
||||||
|
zabbixSession.zabbixPassword = getVaultData(vaultPath, vaultToken, zabbixSession.zabbixUser)
|
||||||
|
// fmt.Println(imapUser, imapPassword)
|
||||||
|
} else if zabbixSession.zabbixPassword == "" && os.Getenv("ZABBIX_PASSWORD") != "" {
|
||||||
|
zabbixSession.zabbixUser = os.Getenv("ZABBIX_USER")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(useZabbixSender)
|
||||||
|
// ----------------------------------------------------------
|
||||||
|
// Run the operations
|
||||||
|
// Send message
|
||||||
|
if sendMessage {
|
||||||
|
log.Println("Send email message with UUID:", message.messageUUID)
|
||||||
|
msgSendResult = sendEmail(&smtpSession, &message)
|
||||||
|
// Send result into zabbix
|
||||||
|
if useZabbixSender {
|
||||||
|
if msgSendResult {
|
||||||
|
zabbixSender(&zabbixSession, `email.smtp_send.`+direction+`.status`, "OK")
|
||||||
|
} else {
|
||||||
|
zabbixSender(&zabbixSession, `email.smtp_send.`+direction+`.status`, "CRITICAL")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// When using both "send" and "receive",
|
||||||
|
// a 10-second pause between operations is required
|
||||||
|
if sendMessage && receiveMessage {
|
||||||
|
time.Sleep(time.Duration(operationDelay) * time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Receive message
|
||||||
|
if receiveMessage {
|
||||||
|
log.Println("Read email message with UUID:", message.messageUUID, "via", imapSession.imapServer)
|
||||||
|
msgReceiveResult = receiveEmail(&imapSession, &message)
|
||||||
|
// Send result into zabbix
|
||||||
|
if useZabbixSender {
|
||||||
|
if msgReceiveResult {
|
||||||
|
zabbixSender(&zabbixSession, `email.imap_receive.`+direction+`.status`, "OK")
|
||||||
|
} else {
|
||||||
|
zabbixSender(&zabbixSession, `email.imap_receive.`+direction+`.status`, "CRITICAL")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send result into zabbix
|
||||||
|
if useZabbixSender {
|
||||||
|
if msgSendResult && msgReceiveResult {
|
||||||
|
zabbixSender(&zabbixSession, `email.delivery.`+direction+`.status`, "OK")
|
||||||
|
} else {
|
||||||
|
zabbixSender(&zabbixSession, `email.delivery.`+direction+`.status`, "CRITICAL")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
module email-check.go
|
||||||
|
|
||||||
|
go 1.15
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/adubkov/go-zabbix v0.0.0-20170118040903-3c6a95ec4fdc // indirect
|
||||||
|
github.com/emersion/go-imap v1.2.1 // indirect
|
||||||
|
github.com/google/uuid v1.3.0 // indirect
|
||||||
|
)
|
|
@ -0,0 +1,14 @@
|
||||||
|
github.com/adubkov/go-zabbix v0.0.0-20170118040903-3c6a95ec4fdc h1:gqqI4ZPa7uwK+gX9Zgk2AweAh+2dX0FpETcXTsA2TrE=
|
||||||
|
github.com/adubkov/go-zabbix v0.0.0-20170118040903-3c6a95ec4fdc/go.mod h1:ihDXRSVen590YHlXIrv00CcmRrL6pUho/Iwm3ZmM8n8=
|
||||||
|
github.com/emersion/go-imap v1.2.1 h1:+s9ZjMEjOB8NzZMVTM3cCenz2JrQIGGo5j1df19WjTA=
|
||||||
|
github.com/emersion/go-imap v1.2.1/go.mod h1:Qlx1FSx2FTxjnjWpIlVNEuX+ylerZQNFE5NsmKFSejY=
|
||||||
|
github.com/emersion/go-message v0.15.0/go.mod h1:wQUEfE+38+7EW8p8aZ96ptg6bAb1iwdgej19uXASlE4=
|
||||||
|
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21 h1:OJyUGMJTzHTd1XQp98QTaHernxMYzRaOasRir9hUlFQ=
|
||||||
|
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ=
|
||||||
|
github.com/emersion/go-textwrapper v0.0.0-20200911093747-65d896831594/go.mod h1:aqO8z8wPrjkscevZJFVE1wXJrLpC5LtJG7fqLOsPb2U=
|
||||||
|
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||||
|
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||||
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue