update
This commit is contained in:
@@ -1 +0,0 @@
|
|||||||
package app
|
|
||||||
@@ -1,21 +1,12 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
|
||||||
"net/smtp"
|
"net/smtp"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"text/template"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const CONFIG_SMTP_HOST = "smtp.gmail.com"
|
|
||||||
const CONFIG_SMTP_PORT = 587
|
|
||||||
const CONFIG_SENDER_NAME = "HIS <hats.nutech@gmail.com>"
|
|
||||||
const CONFIG_AUTH_EMAIL = "hats.nutech@gmail.com"
|
|
||||||
const CONFIG_AUTH_PASSWORD = "lbfjfuywqktkexij"
|
|
||||||
|
|
||||||
type MailConfig struct {
|
type MailConfig struct {
|
||||||
SMTPHost string
|
SMTPHost string
|
||||||
SMTPPort int
|
SMTPPort int
|
||||||
@@ -25,13 +16,6 @@ type MailConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Mail() *MailConfig {
|
func Mail() *MailConfig {
|
||||||
// dialer := gomail.NewDialer(
|
|
||||||
// CONFIG_SMTP_HOST,
|
|
||||||
// CONFIG_SMTP_PORT,
|
|
||||||
// CONFIG_AUTH_EMAIL,
|
|
||||||
// CONFIG_AUTH_PASSWORD,
|
|
||||||
// )
|
|
||||||
|
|
||||||
port, err := strconv.Atoi(os.Getenv("SMTP_PORT"))
|
port, err := strconv.Atoi(os.Getenv("SMTP_PORT"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("error parsing to int", err.Error())
|
fmt.Println("error parsing to int", err.Error())
|
||||||
@@ -46,45 +30,17 @@ func Mail() *MailConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func SendEmail(to []string, cc []string, subject, message string) error {
|
func SendEmail(to []string, cc []string, name, subject, message, htmlString string) error {
|
||||||
tmpl, err := template.ParseFiles("template/test.html")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Error parsing template: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("qwqwqw", os.Getenv("PORT"))
|
|
||||||
|
|
||||||
type Data struct {
|
|
||||||
Name string
|
|
||||||
Company string
|
|
||||||
}
|
|
||||||
|
|
||||||
data := Data{Name: "Salwa Balqis Sulaeman", Company: "HIS"}
|
|
||||||
|
|
||||||
var buf bytes.Buffer
|
|
||||||
if err := tmpl.Execute(&buf, data); err != nil {
|
|
||||||
log.Fatalf("Error executing template: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// content, err := os.ReadFile("template/test.html")
|
|
||||||
// if err != nil {
|
|
||||||
// fmt.Println("Error reading file:", err)
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
|
|
||||||
htmlString := buf.String()
|
|
||||||
|
|
||||||
sender := "From: " + Mail().SMTPSenderName + "\n"
|
sender := "From: " + Mail().SMTPSenderName + "\n"
|
||||||
subjectt := "Subject: 👋 Hello from Go\n"
|
subjectt := "Subject: " + subject + "\n"
|
||||||
mime := "MIME-version: 1.0;\nContent-Type: text/html; charset=\"UTF-8\";\n\n"
|
mime := "MIME-version: 1.0;\nContent-Type: text/html; charset=\"UTF-8\";\n\n"
|
||||||
body := htmlString
|
body := htmlString
|
||||||
messages := []byte(sender + subjectt + mime + body)
|
messages := []byte(sender + subjectt + mime + body)
|
||||||
|
|
||||||
auth := smtp.PlainAuth("", Mail().AuthEmail, Mail().AuthPassword, Mail().SMTPHost)
|
auth := smtp.PlainAuth("", Mail().AuthEmail, Mail().AuthPassword, Mail().SMTPHost)
|
||||||
smtpAddr := fmt.Sprintf("%s:%d", Mail().SMTPHost, Mail().SMTPPort)
|
smtpAddr := fmt.Sprintf("%s:%d", Mail().SMTPHost, Mail().SMTPPort)
|
||||||
fmt.Println("cek dong", Mail())
|
|
||||||
|
|
||||||
err = smtp.SendMail(smtpAddr, auth, Mail().AuthEmail, append(to, cc...), messages)
|
err := smtp.SendMail(smtpAddr, auth, Mail().AuthEmail, append(to, cc...), messages)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
1
go.mod
1
go.mod
@@ -3,6 +3,7 @@ module email-notification
|
|||||||
go 1.21.1
|
go 1.21.1
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/google/uuid v1.6.0
|
||||||
github.com/joho/godotenv v1.5.1
|
github.com/joho/godotenv v1.5.1
|
||||||
gorm.io/driver/postgres v1.5.11
|
gorm.io/driver/postgres v1.5.11
|
||||||
gorm.io/gorm v1.25.12
|
gorm.io/gorm v1.25.12
|
||||||
|
|||||||
2
go.sum
2
go.sum
@@ -1,6 +1,8 @@
|
|||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
|
||||||
|
|||||||
67
helper/helper.go
Normal file
67
helper/helper.go
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
package helper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"html/template"
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GenerateSessionID() string {
|
||||||
|
return uuid.New().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseHTML(filePath string, v any) string {
|
||||||
|
tmpl, err := template.ParseFiles(filePath)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error parsing template: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// type Data struct {
|
||||||
|
// Name string
|
||||||
|
// }
|
||||||
|
|
||||||
|
// data := Data{Name: name}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if err := tmpl.Execute(&buf, v); err != nil {
|
||||||
|
log.Fatalf("Error executing template: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func FormatSince(t time.Time) string {
|
||||||
|
now := time.Now()
|
||||||
|
dur := now.Sub(t)
|
||||||
|
|
||||||
|
years := int(dur.Hours() / 24 / 365)
|
||||||
|
if years > 0 {
|
||||||
|
return fmt.Sprintf("%d", years)
|
||||||
|
}
|
||||||
|
|
||||||
|
// months := int(dur.Hours() / 24 / 30)
|
||||||
|
// if months > 0 {
|
||||||
|
// return fmt.Sprintf("%d bulan yang lalu", months)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// days := int(dur.Hours() / 24)
|
||||||
|
// if days > 0 {
|
||||||
|
// return fmt.Sprintf("%d hari yang lalu", days)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// hours := int(dur.Hours())
|
||||||
|
// if hours > 0 {
|
||||||
|
// return fmt.Sprintf("%d jam yang lalu", hours)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// minutes := int(dur.Minutes())
|
||||||
|
// if minutes > 0 {
|
||||||
|
// return fmt.Sprintf("%d menit yang lalu", minutes)
|
||||||
|
// }
|
||||||
|
|
||||||
|
return "baru saja"
|
||||||
|
}
|
||||||
50
main.go
50
main.go
@@ -2,11 +2,9 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"email-notification/app"
|
|
||||||
"email-notification/config"
|
"email-notification/config"
|
||||||
"email-notification/model"
|
"email-notification/middleware"
|
||||||
"email-notification/query"
|
"email-notification/route"
|
||||||
"fmt"
|
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
@@ -15,51 +13,19 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
fmt.Println("Test")
|
log.Println("Email Notification Service")
|
||||||
err := godotenv.Load()
|
err := godotenv.Load()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Error loading .env file")
|
log.Fatal("Error loading .env file")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
http.Handle("/", middleware.ResponseTimeMiddleware(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Write([]byte("Welcome!"))
|
||||||
|
}))
|
||||||
|
|
||||||
db := config.NewDatabase().WithContext(context.Background())
|
db := config.NewDatabase().WithContext(context.Background())
|
||||||
|
|
||||||
to := []string{"teddy.nutech@gmail.com"}
|
route.Route(db)
|
||||||
cc := []string{"teddy.nutech@gmail.com"}
|
|
||||||
subject := "test"
|
|
||||||
message := "test"
|
|
||||||
|
|
||||||
fmt.Println(to, cc, subject, message)
|
|
||||||
|
|
||||||
http.HandleFunc("/birthday-notification", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
|
|
||||||
data := new([]model.Birthday)
|
|
||||||
|
|
||||||
err := query.GetBirthday(db, data, "1", "1")
|
|
||||||
if err != nil {
|
|
||||||
w.WriteHeader(500)
|
|
||||||
w.Write([]byte(err.Error()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("hasil query data", data)
|
|
||||||
|
|
||||||
for _, v := range *data {
|
|
||||||
fmt.Println("Birthday", v.Fullname)
|
|
||||||
sendTo := []string{v.Email}
|
|
||||||
go func() {
|
|
||||||
fmt.Println("sending email...")
|
|
||||||
err := app.SendEmail(sendTo, sendTo, subject, message)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("error", err.Error())
|
|
||||||
w.WriteHeader(500)
|
|
||||||
w.Write([]byte(err.Error()))
|
|
||||||
} else {
|
|
||||||
fmt.Println("email sent")
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Write([]byte("success"))
|
|
||||||
})
|
|
||||||
|
|
||||||
port := os.Getenv("PORT")
|
port := os.Getenv("PORT")
|
||||||
|
|
||||||
|
|||||||
17
middleware/middleware.go
Normal file
17
middleware/middleware.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ResponseTimeMiddleware(next http.HandlerFunc) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
start := time.Now()
|
||||||
|
path := r.URL.Path
|
||||||
|
next(w, r)
|
||||||
|
duration := time.Since(start)
|
||||||
|
log.Printf("%+v response time %+v", path, duration)
|
||||||
|
}
|
||||||
|
}
|
||||||
123
route/route.go
Normal file
123
route/route.go
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
package route
|
||||||
|
|
||||||
|
import (
|
||||||
|
"email-notification/app"
|
||||||
|
"email-notification/helper"
|
||||||
|
"email-notification/middleware"
|
||||||
|
"email-notification/model"
|
||||||
|
"email-notification/query"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Route(db *gorm.DB) {
|
||||||
|
http.HandleFunc("/birthday-notification", middleware.ResponseTimeMiddleware(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
sessionID := helper.GenerateSessionID()
|
||||||
|
module := "BIRTHDAY NOTIFICATION"
|
||||||
|
log.Printf("%+v %+v request %+v", sessionID, module, nil)
|
||||||
|
|
||||||
|
data := new([]model.Birthday)
|
||||||
|
|
||||||
|
month := int(time.Now().Month())
|
||||||
|
day := time.Now().Day()
|
||||||
|
subject := "Happy Birthday 🎉🎂🥳"
|
||||||
|
|
||||||
|
err := query.GetBirthday(db, data, fmt.Sprint(month), fmt.Sprint(day))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("%+v %+v response %+v", sessionID, module, err.Error())
|
||||||
|
w.WriteHeader(500)
|
||||||
|
w.Write([]byte(err.Error()))
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range *data {
|
||||||
|
fmt.Println("Birthday", v.Fullname)
|
||||||
|
|
||||||
|
sendTo := []string{v.Email}
|
||||||
|
|
||||||
|
type Data struct {
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
|
data := Data{Name: v.Fullname}
|
||||||
|
|
||||||
|
htmlString := helper.ParseHTML("template/birthday.html", data)
|
||||||
|
|
||||||
|
go func(v model.Birthday) {
|
||||||
|
log.Printf("%+v %+v SENDING EMAIL TO %+v", sessionID, module, v.Email)
|
||||||
|
err := app.SendEmail(sendTo, sendTo, "", subject, "", htmlString)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("%+v %+v response %+v", sessionID, module, err.Error())
|
||||||
|
w.WriteHeader(500)
|
||||||
|
w.Write([]byte(err.Error()))
|
||||||
|
} else {
|
||||||
|
log.Fatalf("%+v %+v EMAIL SENT TO %+v", sessionID, module, v.Email)
|
||||||
|
}
|
||||||
|
}(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("%+v %+v response %+v", sessionID, module, "success")
|
||||||
|
w.Write([]byte("success"))
|
||||||
|
}))
|
||||||
|
|
||||||
|
http.HandleFunc("/workanniversary-notification", middleware.ResponseTimeMiddleware(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
sessionID := helper.GenerateSessionID()
|
||||||
|
module := "WORKANNIVERSARY NOTIFICATION"
|
||||||
|
log.Printf("%+v %+v request %+v", sessionID, module, nil)
|
||||||
|
|
||||||
|
data := new([]model.Workanniversary)
|
||||||
|
|
||||||
|
month := int(time.Now().Month())
|
||||||
|
day := time.Now().Day()
|
||||||
|
|
||||||
|
err := query.GetWorkanniversary(db, data, fmt.Sprint(month), fmt.Sprint(day))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("%+v %+v response %+v", sessionID, module, err.Error())
|
||||||
|
w.WriteHeader(500)
|
||||||
|
w.Write([]byte(err.Error()))
|
||||||
|
}
|
||||||
|
|
||||||
|
subject := "Work Anniversary 🎉"
|
||||||
|
|
||||||
|
for _, v := range *data {
|
||||||
|
fmt.Println("Workanniversary", v.Fullname)
|
||||||
|
|
||||||
|
sendTo := []string{v.Email}
|
||||||
|
|
||||||
|
type Data struct {
|
||||||
|
Name string
|
||||||
|
Year string
|
||||||
|
}
|
||||||
|
|
||||||
|
duration := helper.FormatSince(v.HireDate)
|
||||||
|
|
||||||
|
fmt.Println("durasi", duration)
|
||||||
|
|
||||||
|
data := Data{Name: v.Fullname, Year: duration}
|
||||||
|
|
||||||
|
htmlString := helper.ParseHTML("template/workanniversary.html", data)
|
||||||
|
|
||||||
|
go func(v model.Workanniversary) {
|
||||||
|
log.Printf("%+v %+v SENDING EMAIL TO %+v", sessionID, module, v.Email)
|
||||||
|
err := app.SendEmail(sendTo, sendTo, "", subject, "", htmlString)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("%+v %+v response %+v", sessionID, module, err.Error())
|
||||||
|
w.WriteHeader(500)
|
||||||
|
w.Write([]byte(err.Error()))
|
||||||
|
} else {
|
||||||
|
log.Fatalf("%+v %+v EMAIL SENT TO %+v", sessionID, module, v.Email)
|
||||||
|
}
|
||||||
|
}(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("%+v %+v response %+v", sessionID, module, "success")
|
||||||
|
w.Write([]byte("success"))
|
||||||
|
}))
|
||||||
|
|
||||||
|
http.HandleFunc("/test", middleware.ResponseTimeMiddleware(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Write([]byte("success"))
|
||||||
|
}))
|
||||||
|
}
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
<title>Selamat Ulang Tahun!</title>
|
<title>Selamat Ulang Tahun!</title>
|
||||||
<style>
|
<style>
|
||||||
.container {
|
.container {
|
||||||
max-width: 600px;
|
max-width: 100%;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
padding: 30px;
|
padding: 30px;
|
||||||
background-color: #fef9f4;
|
background-color: #fef9f4;
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
</p>
|
</p>
|
||||||
<p class="footer">
|
<p class="footer">
|
||||||
Salam hangat dari kami,<br />
|
Salam hangat dari kami,<br />
|
||||||
<b>Tim {{.Company}}</b>
|
<b>HIS</b>
|
||||||
</p>
|
</p>
|
||||||
<img
|
<img
|
||||||
src="http://36.66.3.44:9000/create-bucket-test/test-folder/LOGO_HIS_NI_New_Contrasted-removebg-preview.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=BDYv2npRYZw5fcXzd80c%2F20250417%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20250417T045323Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=c399ff0031b0d8bc9b7073171bca8ad3a9c2b82a374e25e60dbd35bd5bd5775e"
|
src="http://36.66.3.44:9000/create-bucket-test/test-folder/LOGO_HIS_NI_New_Contrasted-removebg-preview.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=BDYv2npRYZw5fcXzd80c%2F20250417%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20250417T045323Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=c399ff0031b0d8bc9b7073171bca8ad3a9c2b82a374e25e60dbd35bd5bd5775e"
|
||||||
83
template/workanniversary.html
Normal file
83
template/workanniversary.html
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<title>Work Anniversary</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: "Segoe UI", Tahoma, sans-serif;
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.email-container {
|
||||||
|
max-width: 100%;
|
||||||
|
margin: 30px auto;
|
||||||
|
background-color: #ffffff;
|
||||||
|
padding: 25px;
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid #e0e0e0;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
background-color: #00add8;
|
||||||
|
color: #ffffff;
|
||||||
|
padding: 20px;
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 6px 6px 0 0;
|
||||||
|
}
|
||||||
|
.header h1 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
padding: 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.content h2 {
|
||||||
|
color: #00add8;
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
.content p {
|
||||||
|
color: #444;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
.logo {
|
||||||
|
width: 80px;
|
||||||
|
margin: 20px auto;
|
||||||
|
}
|
||||||
|
.footer {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #888;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 30px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="email-container">
|
||||||
|
<div class="header">
|
||||||
|
<h1>🎉 Work Anniversary!</h1>
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
<img
|
||||||
|
src="http://36.66.3.44:9000/create-bucket-test/test-folder/LOGO_HIS_NI_New_Contrasted-removebg-preview.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=BDYv2npRYZw5fcXzd80c%2F20250417%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20250417T045323Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=c399ff0031b0d8bc9b7073171bca8ad3a9c2b82a374e25e60dbd35bd5bd5775e"
|
||||||
|
alt="logo"
|
||||||
|
width="100px"
|
||||||
|
/>
|
||||||
|
<h2>Hai {{.Name}},</h2>
|
||||||
|
<p>
|
||||||
|
Hari ini menandai tahun ke-<strong>{{.Year}}</strong> kamu di
|
||||||
|
perusahaan ini. Terima kasih atas dedikasi, semangat, dan kontribusimu
|
||||||
|
selama ini!
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Kami bangga memiliki kamu dalam tim teknologi kami. Mari terus
|
||||||
|
berkembang bersama — satu commit, satu deploy, satu milestone pada
|
||||||
|
satu waktu. 🚀
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="footer">© HIS 💙</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user