opensmtpd.org 55 KB

(service (@ (gnu services mail) opensmtpd-service-type) ((@ (gnu services mail) opensmtpd-configuration) (config-file …)))

tasks

PROJECT it might be a good idea to change the syntax of this service

    :LOGBOOK:
  • State "TODO" from [2021-11-03 Wed 13:50]
  • :END:

use a simple 1-1 mapping

"...as I think Guix services ought to faithfully wrap the native syntax whenever possible (implement alternative simple APIs on top of that — fine)."

-nckx from irc on #guix

Before I was following nckx's advice on the opensmtpd-service-type, a 1-1 mapping of the smtpd.conf syntax. I was avoiding doing something like this.


  (service email-service-type
           (email-configuration
            (domains (list "gnucode.me" "gnu-hurd.com"))
            (use-letsencrypt #t)))

Instead try to do something like this:


  (service opensmtpd-service
           (opensmtpd-configuration
            (includes ...)
            (tables ...)
            (pkis ...)
            (filters ...)
            (listen-on ...)
            (actions ...)
            (matches ...)))

BUT it would be better if a make the service syntax a little more schemey.

This would eliminate misspelling errors and ensure each has a corresponding and give appropriate error messages. The goal of a lot of this is to minimize the number of times a user has to grok the service's original non-guile syntax file.

Why don't I delete the opensmtpd-configuration's fieldnames 'filters', 'pkis', 'actions', 'mda-wrapper', 'cas'?

So instead of


  (service opensmtpd-service-type
               (opensmtpd-configuration
                (pkis (list
                       (opensmtpd-pki
                        ...)))
                (tables (list
                         (opensmtpd-table
                          ...)
                         (opensmtpd-table
                          ...)))
                (listen-ons
                 (list
                  (opensmtpd-listen-on
                   ...)
                  (opensmtpd-listen-on
                   ...)))
                (actions
                 (list
                  (opensmtpd-action
                     ...)
                  (opensmtpd-action
                   ...)))
                (matches (list
                          (opensmtpd-match
                           ...)
                          (opensmtpd-match
                           ...)))
                (filter-chains
                 (list
                  (opensmtpd-filter-chain
                   (name "dropDumbEmails")
                   (filter-names (list "nofcrdnsDisconnect"
                                       "nordnsDisconnect")))))
                (filter-phases
                 (list (opensmtpd-filter-phase
                        ...)
                       (opensmtpd-filter-phase
                        ...)))))

I'll have this:


  (service opensmtpd-service-type
           (opensmtpd-configuration
            (listen-ons
             (list (opensmtpd-listen-on
                    (interface "eth0")
                    (filter
                     (opensmtpd-filter-chain-configuration
                      (list
                       (opensmtpd-filter-phase
                        ...)
                       (opensmtpd-filter-phase
                        ...))))
                    (hostnames (opensmtpd-table-configuration
                                (values "gnucode.me" "gnu-hurd.com")))
                    (ca
                     (opensmtpd-ca-configuration ...))
                    (pkis
                     (list
                      (opensmtpd-pki-configuration
                       ...)
                      (opensmtpd-pki-configuration
                       ...))))))
            (matches
             (list
              (opensmtpd-match
               (for (opensmtpd-match-option-configuration ...)
               (action
                (opensmtpd-action
                 (opensmtpd-local-delivery-configuration
                  (method
                   (opensmtpd-maildir-configuration
                    ...))
                  (alias (opensmtpd-table
                          ...))))))

DONE remove opensmtpd-configuration-pkis. [4/4] [100%]

    CLOSED: [2021-11-08 Mon 19:01] :LOGBOOK:
  • State "DONE" from "TODO" [2021-11-08 Mon 19:01]
  • State "TODO" from [2021-11-04 Thu 08:36]
  • :END:

Instead of

This is done, I just need to test it.


  (service opensmtpd-service-type
                 (opensmtpd-configuration
                  (pkis (list
                         (opensmtpd-pki
                          (domain "smtp.gnucode.me")
                          (cert "/etc/letsencrypt/live/gnucode.me/fullchain.pem")
                          (key "/etc/letsencrypt/live/gnucode.me/privkey.pem"))))
                  (listen-ons
                   (list
                    (opensmtpd-listen-on
                     (interface "eth0")
                     (port 465)
                     (secure-connection "smtps")
                     (pki "smtp.gnucode.me")
                     (auth "creds"))
                    (opensmtpd-listen-on
                     (interface "eth0")
                     (port 587)
                     (secure-connection "tls-require")
                     (pki "smtp.gnucode.me")
                     (auth "creds"))))))

I'll have this:


  (let ([gnucode.me (opensmtpd-pki
                     (domain "smtp.gnucode.me") ;; could potentially remove 'domain' fieldname.
                     (cert "/etc/letsencrypt/live/gnucode.me/fullchain.pem")
                     (key "/etc/letsencrypt/live/gnucode.me/privkey.pem"))])
    (service opensmtpd-service-type
             (opensmtpd-configuration

              (listen-ons
               (list
                (opensmtpd-listen-on
                 (interface "eth0")
                 (port 465)
                 (secure-connection "smtps")
                 (pki gnucode.me) 
                 (auth "creds"))
                (opensmtpd-listen-on
                 (interface "eth0")
                 (port 587)
                 (secure-connection "tls-require")
                 (pki gnucode.me) 
                 (auth "creds")))))))

However, newbie guix users could instead of using the let, they could

write the same pki more verbosely.


  (service opensmtpd-service-type
           (opensmtpd-configuration
            (listen-ons
             (list
              (opensmtpd-listen-on
               (interface "eth0")
               (port 465)
               (secure-connection "smtps")
               (pki (opensmtpd-pki ;; this pki is written twice
                     (domain "smtp.gnucode.me") 
                     (cert "/etc/letsencrypt/live/gnucode.me/fullchain.pem")
                     (key "/etc/letsencrypt/live/gnucode.me/privkey.pem"))) 
               (auth "creds"))
              (opensmtpd-listen-on
               (interface "eth0")
               (port 587)
               (secure-connection "tls-require")
               (pki (opensmtpd-pki ;; this pki is written twice
                     (domain "smtp.gnucode.me") 
                     (cert "/etc/letsencrypt/live/gnucode.me/fullchain.pem")
                     (key "/etc/letsencrypt/live/gnucode.me/privkey.pem")))
               (auth "creds"))))))

DONE To do make this change, I'll have to iterate over all of the opensmtpd-listen-on records and

DONE This configuration will NOT allow you to reconfigure, but smtpd will refuse to start

    CLOSED: [2021-11-08 Mon 18:52] :LOGBOOK:
  • State "DONE" from "TODO" [2021-11-08 Mon 18:52]
  • State "TODO" from [2021-11-08 Mon 18:52]
  • :END: opensmtpd-action-records and pull out the unique opensmtpd-pki records. and I might need to change opensmtpd-pki to opensmtpd-pki-configuration. CLOSED: [2021-11-08 Mon 19:01] :LOGBOOK:
  • State "DONE" from "TODO" [2021-11-08 Mon 19:01]
  • State "TODO" from "DONE" [2021-11-08 Mon 18:53]
  • State "DONE" from "TODO" [2021-11-08 Mon 18:53]
  • State "TODO" from [2021-11-08 Mon 18:53]
  • :END:

Basically, there is an opensmtpd-match that calls an opensmtpd-action "send". BUT there is no such action defined. This error will not be possible when, task: remove opensmtpd-configuration-actions. Instead add a "action" fieldname to opensmtpd-match. is done.


  (service opensmtpd-service-type
                 (opensmtpd-configuration
                  (tables (list
                           (opensmtpd-table
                            (name "aliases")
                            (values
                             (list
                              (cons "webmaster" "root")
                              (cons "postmaster" "root")
                              (cons "abuse" "root"))))
                           (opensmtpd-table
                            (name "creds")
                            (values
                             (list
                              (cons "joshua"
                                    "$6$Ec4m8FgKjT2F/03Y$k66ABdse9TzCX6qaALB3WBL9GC1rmAWJmaoSjFMpbhzat7DOpFqpnOwpbZ34wwsQYIK8RQlqwM1I/v6vsRq86."))))
                           (opensmtpd-table
                            (name "vdoms")
                            (values (list "gnucode.me"
                                          "gnu-hurd.com")))
                           (opensmtpd-table
                            (name "vusers")
                            (values (list (cons "joshua@gnucode.me" "joshua")
                                          (cons "jbranso@gnucode.me" "joshua")
                                          (cons "postmaster@gnucode.me" "joshua"))))))
                  (listen-ons
                   (list
                    ;; this forum help suggests that I listen on 0.0.0.0 and NOT eth0
                    ;; https://serverfault.com/questions/726795/opensmtpd-wont-work-at-reboot
                    ;; this listens for email from the outside world
                    (opensmtpd-listen-on
                     (interface interface)
                     (port 25)
                     (secure-connection "tls")
                     (pki smtp.gnucode.me)
                     )
                    ;; this lets local users logged into the system via ssh send email
                    (opensmtpd-listen-on
                     (interface "lo")
                     (port 25)
                     (secure-connection "tls")
                     (pki smtp.gnucode.me))
                    (opensmtpd-listen-on
                     (interface interface)
                     (port 465)
                     (secure-connection "smtps")
                     (pki smtp.gnucode.me)
                     (auth "creds"))
                    (opensmtpd-listen-on
                     (interface interface)
                     (port 587)
                     (secure-connection "tls-require")
                     (pki smtp.gnucode.me)
                     (auth "creds"))))
                  (actions
                   (list
                    (opensmtpd-action
                     (name "receive")
                     (method 
                      (opensmtpd-local-delivery-configuration
                       (method (opensmtpd-maildir-configuration
                                (pathname "/home/%{rcpt.user}/Maildir")
                                (junk #t)))
                       (virtual "vusers"))))
                    ))
                  (matches (list
                            (opensmtpd-match
                             (name "send")
                             (for "for any")
                             (from "from any")
                             (auth #t))
                            (opensmtpd-match
                             (name "receive")
                             (from "from any")
                             (for "for domain <vdoms>"))
                            (opensmtpd-match
                             (name "receive")
                             (for "for local"))))
                  (filter-chains
                   (list
                    (opensmtpd-filter-chain
                     (name "dropDumbEmails")
                     (filter-names (list "nofcrdnsDisconnect"
                                         "nordnsDisconnect")))))
                  (filter-phases
                   (list (opensmtpd-filter-phase
                          (name "nofcrdnsDisconnect")
                          (phase-name "connect")
                          (conditions (list "!fcrdns"))
                          (decision "disconnect")
                          (message "You have not set up forward confirmed DNS."))
                         (opensmtpd-filter-phase
                          (name "nordnsDisconnect")
                          (phase-name "connect")
                          (conditions (list "!rdns"))
                          (decision "reject")
                          (message "You have not set up reverse DNS."))))))

DONE users can specify a (listen-on (pki "smtp.gnucode.me")) but not put the pki in a listen-on record.

    CLOSED: [2021-11-05 Fri 05:52] :LOGBOOK:
  • State "DONE" from "TODO" [2021-11-05 Fri 05:52]
  • State "TODO" from [2021-11-03 Wed 17:37]
  • :END:

For example, this is incorrect.


  (service opensmtpd-service-type
         (listen-on (pki "smtpd.gnucode.me")))

But this is correct


  (service opensmtpd-service-type
           (pkis
            (list (opensmtpd-pki
                   (cert "/path/to/cert")
                   (key "/path/to/key"))))
         (listen-on (pki "smtpd.gnucode.me")))

Perhaps I should sanitize the opensmtpd-listen-on pki fieldname. I should check to see if that pki name is in the opensmtpd-configuration-pkis list.

Here is a big example that makes this mistake.


  (opensmtpd-configuration
                  (mta-max-deferred 50)
                  (queue
                   (opensmtpd-queue-configuration
                    (compression #t)))
                  (smtp
                   (opensmtpd-smtp-configuration
                    (max-message-size "10M")))
                  (srs
                   (opensmtpd-srs-configuration
                    (ttl-delay "5d")))
                  ;; (pkis (list
                  ;;        (opensmtpd-pki
                  ;;         (domain "smtpd.gnucode.me")
                  ;;         (cert "/etc/letsencrypt/live/gnucode.me/fullchain.pem")
                  ;;         (key "/etc/letsencrypt/live/gnucode.me/privkey.pem"))))
                  (tables (list
                           (opensmtpd-table
                            (name "aliases")
                            (values
                             (list
                              (cons "webmaster" "root")
                              (cons "postmaster" "root")
                              (cons "abuse" "root"))))
                           (opensmtpd-table
                            (name "creds")
                            (values
                             (list
                              (cons "joshua"
                                    "$6$Ec4m8FgKjT2F/03Y$k66ABdse9TzCX6qaALB3WBL9GC1rmAWJmaoSjFMpbhzat7DOpFqpnOwpbZ34wwsQYIK8RQlqwM1I/v6vsRq86."))))
                           (opensmtpd-table
                            (name "vdoms")
                            (values (list "gnucode.me"
                                          "gnu-hurd.com")))
                           (opensmtpd-table
                            (name "vusers")
                            (values (list (cons "joshua@gnucode.me" "joshua")
                                          (cons "jbranso@gnucode.me" "joshua")
                                          (cons "postmaster@gnucode.me" "joshua"))))))
                  (listen-ons
                   (list
                    ;; this forum help suggests that I listen on 0.0.0.0 and NOT eth0
                    ;; https://serverfault.com/questions/726795/opensmtpd-wont-work-at-reboot
                    ;; this listens for email from the outside world
                    (opensmtpd-listen-on
                     (interface interface)
                     (port 25)
                     (secure-connection "tls")
                     (pki "smtp.gnucode.me"))
                    ;; this lets local users logged into the system via ssh send email
                    (opensmtpd-listen-on
                     (interface "lo")
                     (port 25)
                     (secure-connection "tls")
                     (pki "smtp.gnucode.me"))
                    (opensmtpd-listen-on
                     (interface interface)
                     (port 465)
                     (secure-connection "smtps")
                     (pki "smtp.gnucode.me")
                     (auth "<creds>"))
                    (opensmtpd-listen-on
                     (interface interface)
                     (port 587)
                     (secure-connection "tls-require")
                     (pki "smtp.gnucode.me")
                     (auth "<creds>"))))
                  (actions
                   (list
                    (opensmtpd-action
                     (name "receive")
                     (method 
                      (opensmtpd-local-delivery-configuration
                       (method (opensmtpd-maildir-configuration
                                (pathname "/home/%{rcpt.user}/Maildir")
                                (junk #t)))
                       (virtual "vusers"))))
                    (opensmtpd-action
                     (name "send")
                     (method (opensmtpd-relay-configuration)))))
                  (matches (list
                            (opensmtpd-match
                             (name "send")
                             (for "for any")
                             (from "from any")
                             (auth "auth"))
                            (opensmtpd-match
                             (name "receive")
                             (from "from any")
                             (for "for domain <vdoms>"))
                            (opensmtpd-match
                             (name "receive")
                             (for "for local"))))
                  (filter-chains
                   (list
                    (opensmtpd-filter-chain
                     (name "dropDumbEmails")
                     (filter-names (list "nofcrdnsDisconnect"
                                         "nordnsDisconnect")))))
                  (filter-phases
                   (list (opensmtpd-filter-phase
                          (name "nofcrdnsDisconnect")
                          (phase-name "connect")
                          (conditions (list "!fcrdns"))
                          (decision "disconnect")
                          (message "You have not set up forward confirmed DNS."))
                         (opensmtpd-filter-phase
                          (name "nordnsDisconnect")
                          (phase-name "connect")
                          (conditions (list "!rdns"))
                          (decision "reject")
                          (message "You have not set up reverse DNS.")))))

DONE make the 'cert' and 'key' of pki only use file-exists? when I submit it upstream instead of string?

    CLOSED: [2021-11-05 Fri 05:52] :LOGBOOK:
  • State "DONE" from "TODO" [2021-11-05 Fri 05:52]
  • State "TODO" from [2021-11-03 Wed 18:53]
  • :END:

But string? lets me test the config locally.

TODO are many of my opensmtpd-configuration-'fieldname'->string procedures assuming those fieldnames have values?

    :LOGBOOK:
  • State "TODO" from [2021-11-08 Mon 04:46]
  • :END:

For example, opensmtpd-configuration-pkis returns a list of opensmtpd-configuration-pkis...What if this particular configuration does NOT have any defined pkis? What if it is only for serving local mail?

What about opensmtpd-configuration-filters->string is this assuming that there are filters?

What about opensmtpd-configuration-listen-ons? It's possible that the user uses the default listen-on-socket.

opensmtpd--liston-on-socket-configuration

TODO remove opensmtpd-configuration-filters

    :LOGBOOK:
  • State "TODO" from [2021-11-05 Fri 05:37]
  • :END:

Instead add a fieldname 'filters' to .

TODO remove opensmtpd-configuration-procs

    :LOGBOOK:
  • State "TODO" from [2021-11-05 Fri 08:37]
  • :END:

This


  (opensmtpd-configuration
     (opensmtpd-listen-ons
      (list (opensmtpd-listen-on
             (interface "eth0")
             (filter (filter-proc
                      (name "name")
                      (command "command")))))))

instead of


  (opensmtpd-configuration
   (procs (list
           (filter-proc (name "name")
                        (command "command"))))
   (opensmtpd-listen-ons
    (list (opensmtpd-listen-on
           (filter "name")))))

Do I need a new record type for filter-proc?

filter-proc is not like the other filters...

A filter proc refers to a line like:

proc "proc-name" command

which allows different filters to use the same process.

TODO remove opensmtpd-configuration-tables, which is a list of opensmtpd-tables.

    :LOGBOOK:
  • State "TODO" from [2021-11-05 Fri 06:07]
  • :END:

This would eleminate the possibility of errors such as creating a table name and then misspelling the table name later on in the configuration. Or defining a table but never using it.

For example, this is probably easier


  (opensmtpd-configuration
   (actions (list
             (opensmtpd-action
              (name "relay")
              (method (opensmtpd-relay-configuration
                       (domain (opensmtpd-table
                                ;;(name "domains")  ;; with some smart coding, the name would NOT be needed.
                                (values (list
                                         "gnucode.me"
                                         "gnu-hurd.com"))))))))))

than the alternative:


  (opensmtpd-configuration
   (tables (list
            (opensmtpd-table
             (name "domains")
             (values (list
                      "gnucode.me"
                      "gnu-hurd.com")))))
   (actions (list
             (opensmtpd-action
              (name "relay")
              (method (opensmtpd-relay-configuration
                       (domain "domains")))))))
What directives accept a table?
opensmtpd-local-delivery-configuration [0/3]
opensmtpd-relay-configuration [0/4]
opensmtpd-listen-on [0/4]
opensmtpd-match [0/19]
    ******* TODO alias :LOGBOOK:
  • State "TODO" from [2021-11-02 Tue 03:53]
  • :END: ******* TODO userbase :LOGBOOK:
  • State "TODO" from [2021-11-02 Tue 03:53]
  • :END: ******* TODO virtual :LOGBOOK:
  • State "TODO" from [2021-11-02 Tue 03:53]
  • :END: ******* TODO helo-src :LOGBOOK:
  • State "TODO" from [2021-11-02 Tue 04:00]
  • :END: ******* TODO domain :LOGBOOK:
  • State "TODO" from [2021-11-02 Tue 04:00]
  • :END: ******* TODO auth :LOGBOOK:
  • State "TODO" from [2021-11-02 Tue 04:00]
  • :END: ******* TODO src :LOGBOOK:
  • State "TODO" from [2021-11-02 Tue 04:01]
  • :END: ******* TODO auth :LOGBOOK:
  • State "TODO" from [2021-11-02 Tue 04:01]
  • :END: ******* TODO auth-optional :LOGBOOK:
  • State "TODO" from [2021-11-02 Tue 04:01]
  • :END: ******* TODO hostnames :LOGBOOK:
  • State "TODO" from [2021-11-02 Tue 04:01]
  • :END: ******* TODO senders :LOGBOOK:
  • State "TODO" from [2021-11-02 Tue 04:08]
  • :END: ******** Here is some potential options for how to implement this ********* list approach Guix probably probably won't like the list approach.

    (openmstpd-match (for (list 'not "for domain regex" (opensmtpd-table (values (list "gnucode.me" "gnu-hurd.com")))))

    
    
    
      (openmstpd-match
       (for
        (list "! for domain"
              (opensmtpd-table
               (values (list "gnucode.me" "gnu-hurd.com"))))))
    

    * opensmtpd-match-options-configuration approach I like this one quite a bit.

    This method is a little bit more verbose. Well I guess it's a lot more verbose. But it's easier for me to properly parse what the user wants.

    I would sanitize the the match-options in the opensmtpd-match-for, openmsmtpd-match-from, opensmtpd-match-auth, opensmtpd-match-helo, opensmtpd-match-mail-from, opensmtpd-match-rcpt-to fieldnames. ********** for

    
      (openmstpd-match
       (for
        (opensmtpd-match-options-configuration 
         (not #t)
         (method "domain regex") ;; valid options for "for" are "domain" or "domain regex"
         (opensmtpd-table
          (values (list "gnucode.me" "gnu-hurd.com"))))))
    

    Do I want a regex fieldname? Probably not. It makes it more verbose...

    
      (openmstpd-match
       (for
        (opensmtpd-match-options-configuration 
         (not #t)
         (regex #t)
         (method "domain") ;; valid options for "for" are "domain"
         (opensmtpd-table
          (values (list "gnucode.me" "gnu-hurd.com"))))))
    

    ** from

    
      (openmstpd-match
       (from
        (opensmtpd-match-options-configuration 
         (not #t)
         (method "rdns regex") ;;valid options for from are "auth" "auth regex", "mail-from" "mail-from regex",
                               ;; "rdns", "rdns regex", "src", "src regex"
         (opensmtpd-table
          (values (list "gnucode.me" "gnu-hurd.com"))))))
    

    Do I want a regex fieldname?

    
      (openmstpd-match
       (from
        (opensmtpd-match-options-configuration 
         (not #t)
         (regex #t)
         (method "rdns") ;;valid options for from are "auth", "mail-from", "rdns", "src"
         (opensmtpd-table
          (values (list "gnucode.me" "gnu-hurd.com"))))))
    

    ** auth

    
      (openmstpd-match
       (auth
        (opensmtpd-match-options-configuration
         (not #t)
         (method "auth regex")
         (opensmtpd-table
          (values (list "gnucode.me" "gnu-hurd.com"))))))
    

    Do I want a regex fieldname?

    
      (openmstpd-match
       (auth
        (opensmtpd-match-options-configuration
         (not #t)
         (regex #t)
         (method "auth") ;; valid options for auth are "auth" or this method can be left blank.
         (opensmtpd-table
          (values (list "gnucode.me" "gnu-hurd.com"))))))
    

    ** mail-from

    
      (openmstpd-match
       (mail-from
        (opensmtpd-match-options-configuration
         (not #t)
         (method "mail from")
         (opensmtpd-table
          (values (list "gnucode.me" "gnu-hurd.com"))))))
    

    ** I tweak opensmtpd-match record and add a opensmtpd-match-options

    
      (opensmtpd-match
       (name "action-name")
       (options
        (list
         (opensmtpd-match-options-configuration
          (method "for domain regex")))
        ))
    
      ******* TODO for domain :LOGBOOK:
    • State "TODO" from [2021-11-02 Tue 04:17]
    • :END: ******* TODO for domain regexp :LOGBOOK:
    • State "TODO" from [2021-11-02 Tue 04:19]
    • :END: ******* TODO for rcpt :LOGBOOK:
    • State "TODO" from [2021-11-02 Tue 04:19]
    • :END: ******* TODO for rcpt regexp :LOGBOOK:
    • State "TODO" from [2021-11-02 Tue 04:19]
    • :END: ******* TODO from auth :LOGBOOK:
    • State "TODO" from [2021-11-02 Tue 04:19]
    • :END: ******* TODO from auth regex :LOGBOOK:
    • State "TODO" from [2021-11-02 Tue 04:20]
    • :END: ******* TODO from mail-from :LOGBOOK:
    • State "TODO" from [2021-11-02 Tue 04:20]
    • :END: ******* TODO from mail-from regexp :LOGBOOK:
    • State "TODO" from [2021-11-02 Tue 04:20]
    • :END: ******* TODO from rdns :LOGBOOK:
    • State "TODO" from [2021-11-02 Tue 04:20]
    • :END: ******* TODO from rdns regex :LOGBOOK:
    • State "TODO" from [2021-11-02 Tue 04:20]
    • :END: ******* TODO from src :LOGBOOK:
    • State "TODO" from [2021-11-02 Tue 04:21]
    • :END: ******* TODO from src regex :LOGBOOK:
    • State "TODO" from [2021-11-02 Tue 04:21]
    • :END: ******* TODO auth :LOGBOOK:
    • State "TODO" from [2021-11-02 Tue 04:21]
    • :END: ******* TODO auth regex :LOGBOOK:
    • State "TODO" from [2021-11-02 Tue 04:21]
    • :END: ******* TODO helo :LOGBOOK:
    • State "TODO" from [2021-11-02 Tue 04:21]
    • :END: ******* TODO mail-from :LOGBOOK:
    • State "TODO" from [2021-11-02 Tue 04:22]
    • :END: ******* TODO mail-from regex :LOGBOOK:
    • State "TODO" from [2021-11-02 Tue 04:22]
    • :END: ******* TODO rcpt-to :LOGBOOK:
    • State "TODO" from [2021-11-02 Tue 04:22]
    • :END: ******* TODO rcpt-to regex :LOGBOOK:
    • State "TODO" from "TODO" [2021-11-02 Tue 04:23]
    • :END:
      changes that must take place for this approach:

      given an , I would need to find all of the tables, and print out the tables.

      This is quite a LOT of changes.

      I would also have to find a way to make sure that even though some directives share the same table, that only one table is exported in the file. OR they are both exported, but are exported under different names.

      I would also have to change the way I do matches. I currently have fieldname 'for', which is just a string. I would have to change that to something that optionally accepts a table

      Instead when something wants to use a table, let the object use the record directly.

      For example instead of

      
      
      
      Instead of supporting directives to have a value of , it may be better to just make sure that when

      a directive refers to an opensmtpd-table-name, that we check to make sure that a table with that name exists.

      This would approach the same benefit that we would get with allowing directives to have a value of , which is essentially ensuring that no would even contain data that would translate into a broken smtpd.conf file.

      The downside is that I would not be able to sanitize match records very well.

      I AM NOT DOING THIS. I am just going to let fieldnames have a value of .

      TODO If I do end up doing this, then I will need a way to loop through the opensmtpd-configuration record and find all of the tables.

      is there a way to loop through each fieldname of a record? Suppose you don't want to hard-code each record name by hand, but instead wanted to loop through each fieldname of a record that anyone wrote. [15:02] any particular sort of record? [15:03] RhodiumToad: yes. [15:05] I'm thinking in the context of (guix records). specifically for my opensmtpd service https://notabug.org/jbranso/linode-guix-system-configuration/src/master/opensmtpd.org#todo-it-might-be-a-good-idea-to-completely-rethink-how-i-am-making-this-service various fieldnames need a . It would be nice to take a look at the and get a list of all of the records. [15:06] I can create a function that hardcodes and checks various places for tables, but it would be nice to programmatically do that instead. [15:07] I don't do guix myself, so I don't know what its records are; but what you wanted is doable in, I believe, all the record implementations in the guile distribution [15:19] RhodiumToad: can you send me a pastebin, or point in the direction of the procedure that I may want to use? [15:21] jab: do you mean something like enum.values() in Java? [15:25] jab: for native records and srfi-9 records, something like (map (lambda (f) ((record-accessor (record-type-descriptor fred) f) fred)) (record-type-fields (record-type-descriptor fred))) will give the values of a record [15:26] ArneBab: that should work. RhodiumToad: thanks! for rnrs records, there are similar functions might even be the same functions, I didn't check the definitions [15:27] Would be nice to have a function that works for them all … of course if you have structs or goops classes then you have a different problem or smobs [15:28] it looks like the equivalent functions for rnrs records require you to check the parent record type yourself, i.e. you get only the fields of the most-derived type, and then have to recurse to the parent [15:33] RhodiumToad: thanks [15:42] ERC>

      PROJECT remove opensmtpd-configuration-actions. Instead add a "action" fieldname to opensmtpd-match. [0/3]

        :LOGBOOK:
      • State "TODO" from [2021-11-05 Fri 06:07]
      • :END:
      
        (opensmtpd-configuration
         (matches
          (list
           (opensmtpd-match
            (options (list
                      (opensmtpd-option ...)
                      (opensmtpd-option ...)))
            (action
             (opensmtpd-action
              (name "some action")
              (method (opensmtpd-relay-configuration
                       ...)))))
           (opensmtpd-match 
            (options (list
                      (opensmtpd-option ...)
                      (opensmtpd-option ...)))
            (opensmtpd-action
             (name "some action")
             (method (opensmtpd-local-delivery-configuration
                      ...)))))))
      

      once remove opensmtpd-action and replace it with is done, the above could become:

      
        (opensmtpd-configuration
         (matches
          (list
           (opensmtpd-match
            (options (list
                      (opensmtpd-option ...)
                      (opensmtpd-option ...)))
            (action
             (opensmtpd-action-relay-configuration
                       ...)))
           (opensmtpd-match 
            (options (list
                      (opensmtpd-option ...)
                      (opensmtpd-option ...)))
            (action
             (opensmtpd-action-local-delivery-configuration
              ...))))))
      

      TODO once remove opensmtpd-configuration-actions. Instead add a "action" fieldname to opensmtpd-match. is done,

        :LOGBOOK:
      • State "TODO" from "TODO" [2021-11-08 Mon 19:02]
      • State "TODO" from [2021-11-08 Mon 19:02]
      • :END: I can make the 'name' fieldname of opensmtpd-local-delivery-action and opensmtpd-relay-configuration-action optional.

      TODO add a procedure opensmtpd-configuraton-actions that will loop through the matches to

        :LOGBOOK:
      • State "TODO" from [2021-11-08 Mon 19:09]
      • :END:

      return all of the unique s.

      TODO make sure that the default opensmtpd config still works.

        :LOGBOOK:
      • State "TODO" from [2021-11-08 Mon 19:13]
      • :END:

      eg:

      
      (service opensmtpd-service-type)
      

      turns into an opensmtpd config file of:

      
      listen on lo
      
      action inbound mbox
      match for local action inbound
      
      action outbound relay
      match from local for any action outbound
      
      
        (actions opensmtpd-configuration-actions
                 (default (list (opensmtpd-action
                                 (name "local")
                                 (method (opensmtpd-local-delivery-configuration
                                          (method "mbox"))))
                                (opensmtpd-action
                                 (name "outbound")
                                 (method (opensmtpd-relay-configuration))))))
      

      PROJECT let's get a decent data structures...then do the changing in coding.

      What's a good way to do ?

      + list of ?

      
        (opensmtpd-match
                  (action (opensmtpd-action
                           ...))
                  (options
                   (list
                    (opensmtpd-match-option)
                    (opensmtpd-match-option)
                    (opensmtpd-match-option))))
      

      DONE with lots of fieldnames whose values are ?

        CLOSED: [2021-11-10 Wed 17:57] :LOGBOOK:
      • State "DONE" from "TODO" [2021-11-10 Wed 17:57]
      • State "TODO" from "DONE" [2021-11-10 Wed 17:49]
      • State "DONE" from "TODO" [2021-11-10 Wed 17:49]
      • State "TODO" from [2021-11-10 Wed 17:49]
      • :END:

      This one is perhaps more verbose but it makes it easier to sanitize and it makes it harder for people to put in the wrong values or bad data.

      
        (opensmtpd-match
         (action (opensmtpd-action-configuration))
         (for
          (opensmtpd-match-option))
         (from
          (opensmtpd-match-option))
         (auth
          (opensmtpd-match-option))
         (helo
          (opensmtpd-match-option))
         (mail-from
          (opensmtpd-match-option))
         (rcpt-to
          (opensmtpd-match-option))
         (tag
          (opensmtpd-match-option))
         (tls
          (opensmtpd-match-option)))
      

      Here is a more flushed out example:

      
        (opensmtpd-match
         (action (opensmtpd-action-configuration))
         (for
          (opensmtpd-match-option-configuration
           (option "domain")
           (not #t)
           (regex #t)
           (value (opensmtpd-table
                   (name "creds")
                   (values (list "somerexg" "another regex"))))))
         (from
          (opensmtpd-match-option-configuration
           (option "auth")
           (not #t)
           (regex #t)
           (value (opensmtpd-table
                   (name "users")
                   (values (list "somerexg" "another regex"))))))
         (auth
          (opensmtpd-match-option
           (option "auth")))
         (helo
          (opensmtpd-match-option))
         (mail-from
          (opensmtpd-match-option))
         (rcpt-to
          (opensmtpd-match-option))
         (tag
          (opensmtpd-match-option))
         (tls
          (opensmtpd-match-option)))
      

      mix of with fieldnames 'for' and 'from' and list of

      
        (opensmtpd-match
         (for
          (opensmtpd-match-option))
         (from
          (opensmtpd-match-option))
         (options (list
                   (opensmtpd-match-option)
                   (opensmtpd-match-option)
                   (opensmtpd-match-option))))
      

      DONE change opensmtpd-action into two records: and

      CLOSED: [2021-11-10 Wed 17:57]

        :LOGBOOK:
      • State "DONE" from "TODO" [2021-11-10 Wed 17:57]
      • State "TODO" from [2021-11-08 Mon 19:30]
      • :END:

      opensmtpd-action-local-delivery and opensmtpd-action-relay-configuration

      Anything that accepts an will now have to support taking an , or .

      Or I can derive create a parent record that has only one fieldname: 'name'...and both opensmtpd-action-local-delivery and opensmtpd-action-relay-configuration can inherit from that common record. BUT (guix records) might not support this...

      
      It made sense to have      opensmtpd-action
                                 opensmtpd-action-name
                                 opensmtpd-action-method
                                        |
                                       / \
                                      /   \
                                     /     \
        <local-delivery-configuration>      <relay-configuration>
              same thing as                       same thing as
        <opensmtpd-local-delivery-action>     <opensmtpd-relay-configuration-action>
      

      It made sense because, local-delivery-configuration has options that apply only it. And relay-configuration has options that apply only to it. But why have 3 records when you could have have two?

      DONE make opensmtpd-smtp-configuration->string work

      To make this change, I'll need to add the 'name' fieldname to and .

      
      (display
       (opensmtpd-smtp-configuration->string
        (opensmtpd-smtp-configuration
         (limit-max-mails 10)
         (limit-max-rcpt 10)
         (max-message-size 10))))
      

      TODO make (opensmtpd-configuration->mixed-text-file example-opensmtpd-config) work

      (opensmtpd-configuration->mixed-text-file example-opensmtpd-config) ice-9/boot-9.scm:1685:16: In procedure raise-exception: In procedure opensmtpd-configuration-smtp: Wrong type argument: #< type: # value: #< package: # config-file: #f bounce: #f cas: #f filter-procs: #f listen-ons: (#< interface: "wlp2s0" family: #f auth: #f auth-optional: #f filter: #f hostname: #f hostnames: #f mask-src: #f no-dsn: #f pki: #< domain: "smtp.gnucode.me" cert: "opensmtpd.scm" key: "opensmtpd.scm" dhe: #f> port: 25 proxy-v2: #f received-auth: #f senders: #f secure-connection: "tls" tag: #f protocols: #f ciphers: #f> #< interface: "lo" family: #f auth: #f auth-optional: #f filter: #f hostname: #f hostnames: #f mask-src: #f no-dsn: #f pki: #< domain: "smtp.gnucode.me" cert: "opensmtpd.scm" key: "opensmtpd.scm" dhe: #f> port: 25 proxy-v2: #f received-auth: #f senders: #f secure-connection: "tls" tag: #f protocols: #f ciphers: #f> #< interface: "wlp2s0" family: #f auth: "creds" auth-optional: #f filter: #f hostname: #f hostnames: #f mask-src: #f no-dsn: #f pki: #< domain: "smtp.gnucode.me" cert: "opensmtpd.scm" key: "opensmtpd.scm" dhe: #f> port: 465 proxy-v2: #f received-auth: #f senders: #f secure-connection: "smtps" tag: #f protocols: #f ciphers: #f> #< interface: "wlp2s0" family: #f auth: "creds" auth-optional: #f filter: #f hostname: #f hostnames: #f mask-src: #f no-dsn: #f pki: #< domain: "smtp.gnucode.me" cert: "opensmtpd.scm" key: "opensmtpd.scm" dhe: #f> port: 587 proxy-v2: #f received-auth: #f senders: #f secure-connection: "tls-require" tag: #f protocols: #f ciphers: #f>) listen-on-socket: #< filter: #f mask-src: #f tag: #f> includes: #f matches: (#< action: #< name: "send" backup: #f backup-mx: #f helo: #f domain: #f host: #f pki: #f srs: #f tls: #f protocols: #f ciphers: #f auth: #f mail-from: #f src: #f> for: "'s fieldname \n'for' is of type . AND the \n's fieldname 'option' can be one of the \nfollowing strings: 'for any', 'for local', 'for domain', 'for rcpt-to'.\n" from: "'s fieldname \n'from' is of type . AND the \n's fieldname 'option' can be one of the \nfollowing strings: 'from any', 'from auth', 'from local', 'from mail-from', 'from rdns', 'from socket', or 'from src'.\n" auth: #< option: "auth" not: #f regex: #f value: #f> helo: #f mail-from: #f rcpt-to: #f tag: #f tls: #f> #< action: #< name: "receive" method: #< pathname: "/home/%{rcpt.user}/Maildir" junk: #t> alias: #f ttl: #f user: #f userbase: #f virtual: "vusers" wrapper: #f> for: "'s fieldname \n'for' is of type . AND the \n's fieldname 'option' can be one of the \nfollowing strings: 'for any', 'for local', 'for domain', 'for rcpt-to'.\n" from: "'s fieldname \n'from' is of type . AND the \n's fieldname 'option' can be one of the \nfollowing strings: 'from any', 'from auth', 'from local', 'from mail-from', 'from rdns', 'from socket', or 'from src'.\n" auth: #f helo: #f mail-from: #f rcpt-to: #f tag: #f tls: #f> #< action: #< name: "receive" method: #< pathname: "/home/%{rcpt.user}/Maildir" junk: #t> alias: #f ttl: #f user: #f userbase: #f virtual: "vusers" wrapper: #f> for: "'s fieldname \n'for' is of type . AND the \n's fieldname 'option' can be one of the \nfollowing strings: 'for any', 'for local', 'for domain', 'for rcpt-to'.\n" from: #f auth: #f helo: #f mail-from: #f rcpt-to: #f tag: #f tls: #f>) mda-wrappers: #f mta-max-deferred: 100 procs: #f queue: #f smtp: #f srs: #f tables: (#< name: "aliases" file: #f file-db: #f values: (("webmaster" . "root") ("postmaster" . "root") ("abuse" . "root")) type: #> #< name: "creds" file: #f file-db: #f values: (("joshua" . "$6$Ec4m8FgKjT2F/03Y$k66ABdse9TzCX6qaALB3WBL9GC1rmAWJmaoSjFMpbhzat7DOpFqpnOwpbZ34wwsQYIK8RQlqwM1I/v6vsRq86.")) type: #> #< name: "vdoms" file: #f file-db: #f values: ("gnucode.me" "gnu-hurd.com") type: #> #< name: "vusers" file: #f file-db: #f values: (("joshua@gnucode.me" . "joshua") ("jbranso@gnucode.me" . "joshua") ("postmaster@gnucode.me" . "joshua")) type: #>)>>

      Entering a new prompt. Type `,bt' for a backtrace or `,q' to continue.

      write out of examples of records that will fail to start or do not make sense.

      Provide appropriate error messages.

      There is a trend of guix services that "work" but are not dummy proof. For example, the XMPP service wants a cert in the format of "

      Shepherd will not tell you the configuration file. You have to manually go searching for the config file. Then you have to manually check the configuration syntax of the file, though the command to start the service may have a flag to check the syntax. Anyway it's annoying. Guix services should be able to get a record and just by looking at the record tell if you have done something silly that will make the service refuse to start or behave in a weird way and provide you appropriate error messages so you don't have to go syntax hunting.

      Examples:

      • could be a filter that is defined but never used, which won't
      • be possible once [[id:89603b3f-7580-4531-8aee-2c115c97adfe][remove opensmtpd-configuration-filters]] is done.
      • (listen-on (interface "doesNotExist"))
      • (smtp-configuration (smtp-max-message-size "10G")) Are you sure you
      • want emails that large?
      • (pki (domain "name") (key "notAKeyfile.txt") (cert
      • "notACertFile.txt")
      • (ca (file "NotACaFile.txt"))

      OpenSMTPD Service documentation

      Opensmtpd service users, may want to consider defining the service in a (let ) statement, like the following example:

      
        (services
         (list
          (service earlyoom-service-type
                     (earlyoom-configuration
                      (prefer-regexp "icecat|chromium|firefox")))
          (let ([interface "wlp2s0"]
                  [smtp.gnucode.me (opensmtpd-pki
                                    (domain "smtp.gnucode.me")
                                    (cert "sway.scm")
                                    (key "sway-service.scm"))])
              (service opensmtpd-service-type
                       (opensmtpd-configuration
                        (tables (list
                                 (opensmtpd-table
                                  (name "aliases")
                                  (values
                                   (list
                                    (cons "webmaster" "root")
                                    (cons "postmaster" "root")
                                    (cons "abuse" "root"))))
                                 (opensmtpd-table
                                  (name "creds")
                                  (values
                                   (list
                                    (cons "joshua"
                                          "$6$Ec4m8FgKjT2F/03Y$k66ABdse9TzCX6qaALB3WBL9GC1rmAWJmaoSjFMpbhzat7DOpFqpnOwpbZ34wwsQYIK8RQlqwM1I/v6vsRq86."))))
                                 (opensmtpd-table
                                  (name "vdoms")
                                  (values (list "gnucode.me"
                                                "gnu-hurd.com")))
                                 (opensmtpd-table
                                  (name "vusers")
                                  (values (list (cons "joshua@gnucode.me" "joshua")
                                                (cons "jbranso@gnucode.me" "joshua")
                                                (cons "postmaster@gnucode.me" "joshua"))))))
                        (listen-ons
                         (list
                          ;; this forum help suggests that I listen on 0.0.0.0 and NOT eth0
                          ;; https://serverfault.com/questions/726795/opensmtpd-wont-work-at-reboot
                          ;; this listens for email from the outside world
                          (opensmtpd-listen-on
                           (interface interface)
                           (port 25)
                           (secure-connection "tls")
                           (pki smtp.gnucode.me)
                           )
                          ;; this lets local users logged into the system via ssh send email
                          (opensmtpd-listen-on
                           (interface "lo")
                           (port 25)
                           (secure-connection "tls")
                           (pki smtp.gnucode.me))
                          (opensmtpd-listen-on
                           (interface interface)
                           (port 465)
                           (secure-connection "smtps")
                           (pki smtp.gnucode.me)
                           (auth "creds"))
                          (opensmtpd-listen-on
                           (interface interface)
                           (port 587)
                           (secure-connection "tls-require")
                           (pki smtp.gnucode.me)
                           (auth "creds"))))
                        (actions
                         (list
                          (opensmtpd-action
                           (name "receive")
                           (method 
                            (opensmtpd-local-delivery-configuration
                             (method (opensmtpd-maildir-configuration
                                      (pathname "/home/%{rcpt.user}/Maildir")
                                      (junk #t)))
                             (virtual "vusers"))))
                          ;; (opensmtpd-action
                          ;;  (name "send")
                          ;;  (method (opensmtpd-relay-configuration)))
                          ))
                        (matches (list
                                  (opensmtpd-match
                                   (name "send")
                                   (for "for any")
                                   (from "from any")
                                   (auth #t))
                                  (opensmtpd-match
                                   (name "receive")
                                   (from "from any")
                                   (for "for domain <vdoms>"))
                                  (opensmtpd-match
                                   (name "receive")
                                   (for "for local"))))))))
          %desktop-services)
      
      • Scheme Variable: opensmtpd-service-type

      This is the type of the OpenSMTPD (https://www.opensmtpd.org) service, whose value should be an opensmtpd-configuration object as in this example:

      ,#+BEGIN_SRC scheme (service opensmtpd-service-type (opensmtpd-configuration (pkis (list ...)) (listen-ons (list ...)) (filters (list ...)) (matches (list ...)) (actions (list ...)))) #+END_SRC

      • Data Type: opensmtpd-configuration

      Data type representing the configuration of opensmtpd.

      • package (default: OPENSMTPD)

      Package object of the OpenSMTPD SMTP server.

      • config-file (default: #f)

      File-like object of the OpenSMTPD configuration file to use. By default it listens on the loopback network interface, and allows for mail from users and daemons on the local machine, as well as permitting email to remote servers. Run man smtpd.conf for more information.

      • actions default:

      #+BEGIN_SRC scheme (list (opensmtpd-action (name "local") (method (opensmtpd-local-delivery-configuration (method "mbox")))) (opensmtpd-action (name "outbound") (method (opensmtpd-relay-configuration)))) #+END_SRC

      A list of <opensmtpd-action> records.

      • bounce
      • filter-chains
      • filter-phases
      • filter-procs
      • filter-proc-execs
      • listen-ons
      • listen-on-socket
      • includes
      • matches
      • mda-wrappers
      • mta-max-deferred
      • pkis
      • procs
      • tables
      • srs
      • smtp
      • queue
      • Data Type: opensmtpd-action

      The data type representing the configuration of an ~~ record.

      • <opensmtpd-action> : name (default: "local")

      The string name of the of the action.

      • <opensmtpd-action> : ~method (default:
      • ~(opensmtpd-local-delivery-configuration)~)

      The local delivery configuration, which is either a <opensmtpd-local-delivery-configuration> or a <opensmtpd-relay-configuration> record.

      • Data Type: opensmtpd-local-delivery-configuration

      The data type representing the configuration of an <opensmtpd-local-delivery-configuration> record.

      • <opensmtpd-local-delivery-configuration> : method (default:
      • ~"mbox"~)

      The local delivery method. Either "mbox", "expand-only", "forward-only", <opensmtpd-lmtp-configuration>, <opensmtpd-maildir-configuration>, or <opensmtpd-mda-configuration>.

      • alias (default: #f)

      Use the mapping table for aliases expansion. alias is a string table name. The string must begin with "<" and end with ">". For example "".

      • ttl (default: )
      • user (default: )
      • userbase (default: )
      • virtual (default: )
      • wrapper (default: )