WIP: mail publish
This commit is contained in:
		
							parent
							
								
									43a2acb756
								
							
						
					
					
						commit
						3001e57bcc
					
				
					 4 changed files with 130 additions and 0 deletions
				
			
		
							
								
								
									
										2
									
								
								go.mod
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								go.mod
									
										
									
									
									
								
							|  | @ -8,6 +8,7 @@ require ( | |||
| 	firebase.google.com/go v3.13.0+incompatible | ||||
| 	github.com/BurntSushi/toml v0.4.1 // indirect | ||||
| 	github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect | ||||
| 	github.com/emersion/go-smtp v0.15.0 | ||||
| 	github.com/mattn/go-sqlite3 v1.14.9 | ||||
| 	github.com/olebedev/when v0.0.0-20211212231525-59bd4edcf9d6 | ||||
| 	github.com/stretchr/testify v1.7.0 | ||||
|  | @ -26,6 +27,7 @@ require ( | |||
| 	github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4 // indirect | ||||
| 	github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490 // indirect | ||||
| 	github.com/davecgh/go-spew v1.1.1 // indirect | ||||
| 	github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21 // indirect | ||||
| 	github.com/envoyproxy/go-control-plane v0.10.1 // indirect | ||||
| 	github.com/envoyproxy/protoc-gen-validate v0.6.2 // indirect | ||||
| 	github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect | ||||
|  |  | |||
							
								
								
									
										4
									
								
								go.sum
									
										
									
									
									
								
							
							
						
						
									
										4
									
								
								go.sum
									
										
									
									
									
								
							|  | @ -89,6 +89,10 @@ github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t | |||
| 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/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||
| 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-smtp v0.15.0 h1:3+hMGMGrqP/lqd7qoxZc1hTU8LY8gHV9RFGWlqSDmP8= | ||||
| github.com/emersion/go-smtp v0.15.0/go.mod h1:qm27SGYgoIPRot6ubfQ/GpiPy/g3PaZAVRxiO/sDUgQ= | ||||
| github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= | ||||
| github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= | ||||
| github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= | ||||
|  |  | |||
							
								
								
									
										102
									
								
								server/mailserver.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								server/mailserver.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,102 @@ | |||
| package server | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"github.com/emersion/go-smtp" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"log" | ||||
| 	"net/http" | ||||
| 	"net/http/httptest" | ||||
| 	"net/mail" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| ) | ||||
| 
 | ||||
| // mailBackend implements SMTP server methods. | ||||
| type mailBackend struct { | ||||
| 	s *Server | ||||
| } | ||||
| 
 | ||||
| func (b *mailBackend) Login(state *smtp.ConnectionState, username, password string) (smtp.Session, error) { | ||||
| 	return &Session{s: b.s}, nil | ||||
| } | ||||
| 
 | ||||
| func (b *mailBackend) AnonymousLogin(state *smtp.ConnectionState) (smtp.Session, error) { | ||||
| 	return &Session{s: b.s}, nil | ||||
| } | ||||
| 
 | ||||
| // Session is returned after EHLO. | ||||
| type Session struct { | ||||
| 	s        *Server | ||||
| 	from, to string | ||||
| 	mu       sync.Mutex | ||||
| } | ||||
| 
 | ||||
| func (s *Session) AuthPlain(username, password string) error { | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (s *Session) Mail(from string, opts smtp.MailOptions) error { | ||||
| 	s.mu.Lock() | ||||
| 	defer s.mu.Unlock() | ||||
| 	s.from = from | ||||
| 	log.Println("Mail from:", from) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (s *Session) Rcpt(to string) error { | ||||
| 	s.mu.Lock() | ||||
| 	defer s.mu.Unlock() | ||||
| 	s.to = to | ||||
| 	log.Println("Rcpt to:", to) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (s *Session) Data(r io.Reader) error { | ||||
| 	s.mu.Lock() | ||||
| 	defer s.mu.Unlock() | ||||
| 	b, err := ioutil.ReadAll(r) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	log.Println("Data:", string(b)) | ||||
| 	msg, err := mail.ReadMessage(bytes.NewReader(b)) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	body, err := io.ReadAll(msg.Body) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	topic := strings.TrimSuffix(s.to, "@ntfy.sh") | ||||
| 	url := fmt.Sprintf("%s/%s", s.s.config.BaseURL, topic) | ||||
| 	req, err := http.NewRequest("PUT", url, bytes.NewReader(body)) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	subject := msg.Header.Get("Subject") | ||||
| 	if subject != "" { | ||||
| 		req.Header.Set("Title", subject) | ||||
| 	} | ||||
| 	rr := httptest.NewRecorder() | ||||
| 	s.s.handle(rr, req) | ||||
| 	if rr.Code != http.StatusOK { | ||||
| 		return errors.New("error: " + rr.Body.String()) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (s *Session) Reset() { | ||||
| 	s.mu.Lock() | ||||
| 	s.from = "" | ||||
| 	s.to = "" | ||||
| 	s.mu.Unlock() | ||||
| } | ||||
| 
 | ||||
| func (s *Session) Logout() error { | ||||
| 	return nil | ||||
| } | ||||
|  | @ -8,6 +8,7 @@ import ( | |||
| 	firebase "firebase.google.com/go" | ||||
| 	"firebase.google.com/go/messaging" | ||||
| 	"fmt" | ||||
| 	"github.com/emersion/go-smtp" | ||||
| 	"google.golang.org/api/option" | ||||
| 	"heckel.io/ntfy/util" | ||||
| 	"html/template" | ||||
|  | @ -238,10 +239,16 @@ func (s *Server) Run() error { | |||
| 			errChan <- s.httpsServer.ListenAndServeTLS(s.config.CertFile, s.config.KeyFile) | ||||
| 		}() | ||||
| 	} | ||||
| 	if true { | ||||
| 		go func() { | ||||
| 			errChan <- s.mailserver() | ||||
| 		}() | ||||
| 	} | ||||
| 	s.mu.Unlock() | ||||
| 	go s.runManager() | ||||
| 	go s.runAtSender() | ||||
| 	go s.runFirebaseKeepliver() | ||||
| 
 | ||||
| 	return <-errChan | ||||
| } | ||||
| 
 | ||||
|  | @ -722,6 +729,21 @@ func (s *Server) updateStatsAndPrune() { | |||
| 		s.messages, len(s.topics), subscribers, messages, len(s.visitors)) | ||||
| } | ||||
| 
 | ||||
| func (s *Server) mailserver() error { | ||||
| 	ms := smtp.NewServer(&mailBackend{s}) | ||||
| 
 | ||||
| 	ms.Addr = ":1025" | ||||
| 	ms.Domain = "localhost" | ||||
| 	ms.ReadTimeout = 10 * time.Second | ||||
| 	ms.WriteTimeout = 10 * time.Second | ||||
| 	ms.MaxMessageBytes = 1024 * 1024 | ||||
| 	ms.MaxRecipients = 50 | ||||
| 	ms.AllowInsecureAuth = true | ||||
| 
 | ||||
| 	log.Println("Starting server at", ms.Addr) | ||||
| 	return ms.ListenAndServe() | ||||
| } | ||||
| 
 | ||||
| func (s *Server) runManager() { | ||||
| 	for { | ||||
| 		select { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue