From b8f2527b93eac4b46b0fd0179d044c4817333847 Mon Sep 17 00:00:00 2001 From: James Hillyerd Date: Wed, 7 Nov 2012 15:26:15 -0800 Subject: [PATCH] Mixed use support You can now optionally configure a "no store" domain. When inbucket receives a message destined for a user at that domain, it will accept the message but not store it to disk. This allows the same instance of Inbucket to be shared by people who wish to view email content and those who want to load test. --- config/config.go | 10 ++++++++++ etc/devel.conf | 4 ++++ etc/inbucket.conf | 4 ++++ smtpd/handler.go | 41 +++++++++++++++++++++++++---------------- smtpd/listener.go | 6 +++++- 5 files changed, 48 insertions(+), 17 deletions(-) diff --git a/config/config.go b/config/config.go index 96a368a..82f1866 100644 --- a/config/config.go +++ b/config/config.go @@ -15,6 +15,7 @@ type SmtpConfig struct { Ip4address net.IP Ip4port int Domain string + DomainNoStore string MaxRecipients int MaxIdleSeconds int MaxMessageBytes int @@ -177,6 +178,15 @@ func parseSmtpConfig() error { } smtpConfig.Domain = str + option = "domain.nostore" + if Config.HasOption(section, option) { + str, err = Config.String(section, option) + if err != nil { + return fmt.Errorf("Failed to parse [%v]%v: '%v'", section, option, err) + } + smtpConfig.DomainNoStore = str + } + option = "max.recipients" smtpConfig.MaxRecipients, err = Config.Int(section, option) if err != nil { diff --git a/etc/devel.conf b/etc/devel.conf index ecb9b14..5d888b6 100644 --- a/etc/devel.conf +++ b/etc/devel.conf @@ -25,6 +25,10 @@ ip4.port=2500 # used in SMTP greeting domain=inbucket.local +# optional: mail sent to accounts at this domain will not be stored, +# for mixed use (content and load testing) +domain.nostore=bitbucket.local + # Maximum number of RCPT TO: addresses we allow from clients, the SMTP # RFC recommends this be at least 100. max.recipients=100 diff --git a/etc/inbucket.conf b/etc/inbucket.conf index ee6e57c..f8ca8b7 100644 --- a/etc/inbucket.conf +++ b/etc/inbucket.conf @@ -25,6 +25,10 @@ ip4.port=2500 # used in SMTP greeting domain=inbucket.local +# optional: mail sent to accounts at this domain will not be stored, +# for mixed use (content and load testing) +#domain.nostore=bitbucket.local + # Maximum number of RCPT TO: addresses we allow from clients, the SMTP # RFC recommends this be at least 100. max.recipients=100 diff --git a/smtpd/handler.go b/smtpd/handler.go index 4c1b991..e2a5768 100644 --- a/smtpd/handler.go +++ b/smtpd/handler.go @@ -300,15 +300,20 @@ func (ss *Session) dataHandler() { i := 0 for e := ss.recipients.Front(); e != nil; e = e.Next() { recip := e.Value.(string) - mb, err := ss.server.dataStore.MailboxFor(recip) - if err != nil { - ss.error("Failed to open mailbox for %v", recip) - ss.send(fmt.Sprintf("451 Failed to open mailbox for %v", recip)) - ss.reset() - return + if !strings.HasSuffix(strings.ToLower(recip), "@" + ss.server.domainNoStore) { + // Not our "no store" domain, so store the message + mb, err := ss.server.dataStore.MailboxFor(recip) + if err != nil { + ss.error("Failed to open mailbox for %v", recip) + ss.send(fmt.Sprintf("451 Failed to open mailbox for %v", recip)) + ss.reset() + return + } + mailboxes[i] = mb + messages[i] = mb.NewMessage() + } else { + log.Trace("Not storing message for '%v'", recip) } - mailboxes[i] = mb - messages[i] = mb.NewMessage() i++ } } @@ -333,8 +338,10 @@ func (ss *Session) dataHandler() { // Mail data complete if ss.server.storeMessages { for _, m := range messages { - m.Close() - expDeliveredTotal.Add(1) + if m != nil { + m.Close() + expDeliveredTotal.Add(1) + } } } else { expDeliveredTotal.Add(1) @@ -360,12 +367,14 @@ func (ss *Session) dataHandler() { // Append to message objects if ss.server.storeMessages { for i, m := range messages { - if err := m.Append(line); err != nil { - ss.error("Failed to append to mailbox %v: %v", mailboxes[i], err) - ss.send("554 Something went wrong") - ss.reset() - // TODO: Should really cleanup the crap on filesystem... - return + if m != nil { + if err := m.Append(line); err != nil { + ss.error("Failed to append to mailbox %v: %v", mailboxes[i], err) + ss.send("554 Something went wrong") + ss.reset() + // TODO: Should really cleanup the crap on filesystem... + return + } } } } diff --git a/smtpd/listener.go b/smtpd/listener.go index f6d8bc7..51c265f 100644 --- a/smtpd/listener.go +++ b/smtpd/listener.go @@ -7,12 +7,14 @@ import ( "github.com/jhillyerd/inbucket/config" "github.com/jhillyerd/inbucket/log" "net" + "strings" "time" ) // Real server code starts here type Server struct { domain string + domainNoStore string maxRecips int maxIdleSeconds int maxMessageBytes int @@ -45,7 +47,7 @@ func New() *Server { cfg := config.GetSmtpConfig() return &Server{dataStore: ds, domain: cfg.Domain, maxRecips: cfg.MaxRecipients, maxIdleSeconds: cfg.MaxIdleSeconds, maxMessageBytes: cfg.MaxMessageBytes, - storeMessages: cfg.StoreMessages} + storeMessages: cfg.StoreMessages, domainNoStore: strings.ToLower(cfg.DomainNoStore)} } // Main listener loop @@ -69,6 +71,8 @@ func (s *Server) Start() { if !s.storeMessages { log.Info("Load test mode active, messages will not be stored") + } else if s.domainNoStore != "" { + log.Info("Messages sent to domain '%v' will be discarded", s.domainNoStore) } // Start retention scanner