watch a specific folder
This commit is contained in:
parent
31c56a3030
commit
3ea64f2fb6
45
README.md
45
README.md
|
@ -2,30 +2,57 @@
|
|||
|
||||
## Setup
|
||||
|
||||
Before running the `imap-json-fetcher`, ensure that the following environment variables are set:
|
||||
Before running the `imap-json-fetcher`, ensure that you have configured the necessary environment variables. This script uses these variables to securely connect to your IMAP server and fetch emails from a specified mailbox.
|
||||
|
||||
- `IMAP_HOST`: Your IMAP server address (e.g., `imap.example.com:993`).
|
||||
- `IMAP_USERNAME`: Your email username.
|
||||
- `IMAP_PASSWORD`: Your email password.
|
||||
### Required Environment Variables
|
||||
|
||||
You can set these environment variables in a Unix-like terminal as follows:
|
||||
Set the following environment variables in your system:
|
||||
|
||||
- `IMAP_HOST`: The address of your IMAP server, including the port if necessary (e.g., `imap.example.com:993`).
|
||||
- `IMAP_USERNAME`: Your email account username.
|
||||
- `IMAP_PASSWORD`: Your email account password.
|
||||
- `IMAP_FOLDER`: The specific folder to monitor for new emails. If not specified, the script defaults to monitoring the "INBOX".
|
||||
|
||||
You can set these variables in a Unix-like environment using the following commands:
|
||||
|
||||
```bash
|
||||
export IMAP_HOST="your_imap_server_address"
|
||||
export IMAP_USERNAME="your_username"
|
||||
export IMAP_PASSWORD="your_password"
|
||||
export IMAP_FOLDER="your_folder_name" # Optional, defaults to "INBOX"
|
||||
```
|
||||
|
||||
## Running the Script
|
||||
### Running the Script
|
||||
|
||||
To run the `imap-json-fetcher`, navigate to the `dist` directory where the binary is located, and use the following command:
|
||||
Navigate to the `dist` directory where the binary is compiled, and run the script using the following command:
|
||||
|
||||
```bash
|
||||
./imap-json-fetcher
|
||||
```
|
||||
|
||||
This assumes that you have already compiled the binary and placed it in the `dist` directory.
|
||||
### Docker Container Example
|
||||
|
||||
For running in a Docker container, you might set it up like this, passing the environment variables into your container. Replace specifics to fit your architecture and environment settings:
|
||||
|
||||
```bash
|
||||
docker run --env IMAP_HOST=$IMAP_HOST \
|
||||
--env IMAP_USERNAME=$IMAP_USERNAME \
|
||||
--env IMAP_PASSWORD=$IMAP_PASSWORD \
|
||||
--env IMAP_FOLDER=$IMAP_FOLDER \
|
||||
--name imap-json-fetcher \
|
||||
your_docker_image
|
||||
```
|
||||
|
||||
This command assumes that you've built a Docker image named `your_docker_image` that encapsulates your application.
|
||||
|
||||
## Output
|
||||
|
||||
The `imap-json-fetcher` will listen for new emails and output the extracted email addresses in separate JSON files, one per email, named in the format `email-seqNum.json`.
|
||||
The `imap-json-fetcher` listens for new emails arriving in the specified IMAP folder. For each new email, it extracts relevant data and saves this information in separate JSON files. The inclusion of the `IMAP_FOLDER` environment variable allows flexibility in choosing which folder to monitor, beyond just the default "INBOX".
|
||||
|
||||
### File Naming Convention
|
||||
|
||||
Output files are named using a timestamp to ensure uniqueness: `email-yyyyMMdd-HHmmss.json`. This format prevents overwriting files and helps in organizing data chronologically.
|
||||
|
||||
## Flexibility in Folder Selection
|
||||
|
||||
The `IMAP_FOLDER` environment variable provides users the flexibility to monitor various folders within their email account, such as "Sent", "Archive", or custom labels, depending on their specific requirements.
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
main.go:2:1: expected 'package', found 'import'
|
|
@ -0,0 +1 @@
|
|||
main.go:2:1: expected 'package', found 'import'
|
|
@ -0,0 +1 @@
|
|||
main.go:2:1: expected 'package', found 'import'
|
|
@ -0,0 +1 @@
|
|||
main.go:2:1: expected 'package', found 'import'
|
|
@ -0,0 +1 @@
|
|||
main.go:2:1: expected 'package', found 'import'
|
|
@ -0,0 +1 @@
|
|||
main.go:2:1: expected 'package', found 'import'
|
|
@ -0,0 +1 @@
|
|||
main.go:2:1: expected 'package', found 'import'
|
|
@ -0,0 +1 @@
|
|||
main.go:2:1: expected 'package', found 'import'
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"body": "test9\r\n",
|
||||
"date": "2024-05-04T13:15:07Z",
|
||||
"from": [
|
||||
{
|
||||
"PersonalName": "",
|
||||
"AtDomainList": "",
|
||||
"MailboxName": "imapfetcher",
|
||||
"HostName": "nixc.us"
|
||||
}
|
||||
],
|
||||
"subject": "test9",
|
||||
"to": [
|
||||
{
|
||||
"PersonalName": "",
|
||||
"AtDomainList": "",
|
||||
"MailboxName": "imapfetcher",
|
||||
"HostName": "nixc.us"
|
||||
}
|
||||
]
|
||||
}
|
11
go.mod
11
go.mod
|
@ -1,14 +1,3 @@
|
|||
module imap-json-fetcher
|
||||
|
||||
go 1.21.1
|
||||
|
||||
require (
|
||||
github.com/emersion/go-imap v1.2.1
|
||||
github.com/emersion/go-message v0.15.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21 // indirect
|
||||
github.com/emersion/go-textwrapper v0.0.0-20200911093747-65d896831594 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
)
|
||||
|
|
12
go.sum
12
go.sum
|
@ -1,12 +0,0 @@
|
|||
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 h1:urgKGqt2JAc9NFJcgncQcohHdiYb803YTH9OQwHBHIY=
|
||||
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 h1:IbFBtwoTQyw0fIM5xv1HF+Y+3ZijDR839WMulgxCcUY=
|
||||
github.com/emersion/go-textwrapper v0.0.0-20200911093747-65d896831594/go.mod h1:aqO8z8wPrjkscevZJFVE1wXJrLpC5LtJG7fqLOsPb2U=
|
||||
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=
|
99
main.go
99
main.go
|
@ -1,4 +1,3 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
@ -11,6 +10,7 @@ import (
|
|||
|
||||
"github.com/emersion/go-imap"
|
||||
"github.com/emersion/go-imap/client"
|
||||
"github.com/emersion/go-imap-idle"
|
||||
"github.com/emersion/go-message/mail"
|
||||
)
|
||||
|
||||
|
@ -18,67 +18,96 @@ func main() {
|
|||
host := os.Getenv("IMAP_HOST")
|
||||
username := os.Getenv("IMAP_USERNAME")
|
||||
password := os.Getenv("IMAP_PASSWORD")
|
||||
folder := os.Getenv("IMAP_FOLDER")
|
||||
if folder == "" {
|
||||
folder = "INBOX"
|
||||
}
|
||||
|
||||
if host == "" || username == "" || password == "" {
|
||||
log.Fatal("Environment variables IMAP_HOST, IMAP_USERNAME, and IMAP_PASSWORD must be set")
|
||||
log.Fatal("Required environment variables are not set")
|
||||
}
|
||||
|
||||
log.Println("Connecting to server...")
|
||||
|
||||
// Connect to the IMAP server
|
||||
c, err := client.DialTLS(host, nil)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to connect to IMAP server: %v", err)
|
||||
}
|
||||
log.Println("Connected")
|
||||
defer c.Logout()
|
||||
|
||||
// Login
|
||||
if err := c.Login(username, password); err != nil {
|
||||
log.Fatalf("Failed to log in: %v", err)
|
||||
}
|
||||
log.Println("Logged in")
|
||||
|
||||
// Select INBOX
|
||||
_, err = c.Select("INBOX", false)
|
||||
log.Println("Logged in and authenticated")
|
||||
|
||||
// Ensure the selected folder is continuously monitored
|
||||
for {
|
||||
if err := monitorFolder(c, folder); err != nil {
|
||||
log.Printf("Error monitoring folder %s: %v", folder, err)
|
||||
log.Println("Attempting to reconnect in 30 seconds...")
|
||||
time.Sleep(30 * time.Second)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func monitorFolder(c *client.Client, folder string) error {
|
||||
_, err := c.Select(folder, false)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to select INBOX: %v", err)
|
||||
return fmt.Errorf("failed to select '%s': %w", folder, err)
|
||||
}
|
||||
|
||||
// Set up criteria to search for new unseen emails
|
||||
criteria := imap.NewSearchCriteria()
|
||||
criteria.WithoutFlags = []string{imap.SeenFlag}
|
||||
ids, err := c.Search(criteria)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to search emails: %v", err)
|
||||
}
|
||||
if len(ids) == 0 {
|
||||
log.Println("No new emails")
|
||||
return
|
||||
}
|
||||
log.Printf("Monitoring folder: %s", folder)
|
||||
idleClient := idle.NewClient(c)
|
||||
done := make(chan error, 1)
|
||||
|
||||
seqset := new(imap.SeqSet)
|
||||
seqset.AddNum(ids...)
|
||||
|
||||
section := &imap.BodySectionName{}
|
||||
items := []imap.FetchItem{section.FetchItem(), imap.FetchEnvelope}
|
||||
messages := make(chan *imap.Message)
|
||||
go func() {
|
||||
if err := c.Fetch(seqset, items, messages); err != nil {
|
||||
log.Fatalf("Failed to fetch emails: %v", err)
|
||||
done <- idleClient.Idle(nil)
|
||||
}()
|
||||
|
||||
for {
|
||||
select {
|
||||
case err := <-done:
|
||||
if err != nil {
|
||||
return fmt.Errorf("idle error: %w", err)
|
||||
}
|
||||
return nil
|
||||
case <-time.After(29 * time.Minute): // Re-initiate IDLE approximately every 29 minutes
|
||||
if err := idleClient.Terminate(); err != nil {
|
||||
log.Printf("Error terminating IDLE: %v", err)
|
||||
}
|
||||
return fmt.Errorf("reinitializing IDLE")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func processNewMessages(c *client.Client, mbox *imap.MailboxStatus) {
|
||||
seqset := new(imap.SeqSet)
|
||||
seqset.AddRange(mbox.Messages, mbox.Messages)
|
||||
|
||||
messages := make(chan *imap.Message, 10)
|
||||
go func() {
|
||||
if err := c.Fetch(seqset, []imap.FetchItem{imap.FetchEnvelope, imap.FetchBody}, messages); err != nil {
|
||||
log.Fatalf("Failed to fetch new messages: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
counter := 0
|
||||
for msg := range messages {
|
||||
processMessage(msg)
|
||||
}
|
||||
}
|
||||
|
||||
// processMessage processes a single message, extracting data and saving to JSON
|
||||
func processMessage(msg *imap.Message) {
|
||||
if msg == nil {
|
||||
continue
|
||||
log.Println("No message to process")
|
||||
return
|
||||
}
|
||||
|
||||
body := msg.GetBody(section)
|
||||
body := msg.GetBody(&imap.BodySectionName{})
|
||||
if body == nil {
|
||||
log.Println("No body fetched for this message")
|
||||
continue
|
||||
return
|
||||
}
|
||||
|
||||
r, err := mail.CreateReader(body)
|
||||
|
@ -122,12 +151,10 @@ func main() {
|
|||
}
|
||||
|
||||
timestamp := time.Now().Format("20060102-150405")
|
||||
fileName := fmt.Sprintf("email-%s-%d.json", timestamp, counter)
|
||||
counter++
|
||||
fileName := fmt.Sprintf("email-%s.json", timestamp)
|
||||
err = os.WriteFile(fileName, emailJSON, 0644)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to write file %s: %v", fileName, err)
|
||||
}
|
||||
log.Printf("Saved %s", fileName)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue