+++ title = "SMTP Gateway with Exim" description = "Start a SMTP server that forwards all mails to docspell." weight = 50 +++ # SMTP Gateway with Exim One possible use case for the [integration endpoint](@/docs/api/upload.md#integration-endpoint) is a SMTP server that forwards all local mail to docspell. This way there is no periodic polling involved and documents (e-mails) get into docspell without delay. The `tools/exim` folder contains a docker file and a sample `exim.conf` to help start with this setup. Note that these files provide a minimal setup, you might want to add tls and spam protection when opening it to the public. # What you need You need to own a domain and add the appropriate MX records to point to your server. In this document, the domain `test.org` is used. You need to enable the [integration endpoint](@/docs/api/upload.md#integration-endpoint) in the docspell configuration. # Exim [Exim](http://exim.org/) is a popular smtp server (message transfer agent). It is used here only because of previous knowledge, but same can be achieved with other MTAs. # The Config File Here is the example config file for exim: {{ incl_conf(path="templates/shortcodes/sample-exim.conf") }} Exim has good [documentation](https://www.exim.org/docs.html), look there for more info. The following is only a quick summary of the file above. The `domainlist local_domains` should list your domain. Only mails to this domain are allowed, as specified in the first rule in `acl_check_rcpt`. So mails to `name@test.org` are ok, but `name@someother.org` not. Another rule in `acl_check_rcpt` executes a `GET` request against the integration endpoint. If that fails, the recipient is wrong (or the endpoint disabled) and the mail is rejected right away. Then the `routers` define how a mail is handled. There is only one router that accepts all mails (that have not been rejected by a rule in acls) and uses the `docspell` transport to deliver it. The transport specifies a command via the `pipe` driver that is run with the mail. The mail itself is provided via stdin. So a simple `curl` command can upload it to the integration endpoint. Here are some quick notes about the used options (see `man curl`): - `--silent` and `--out /dev/null` don't print upload progress information and no output to stdout - `--fail` return non-zero if http status code is not success - `-F` use a multipart/form-data request (defaults to a POST request) - `"file=@-;filename=\"$_subject:\""` add one part with name `file` and take the data from stdin (`@-`). Since there is no filename, we use the subject of the mail. This is [supported by exim](http://exim.org/exim-html-current/doc/html/spec_html/ch-string_expansions.html) by expanding the subject mail header via `$h_subject:` (the colon is required). - `$local_part` this is expanded by exim to the recipient address, only the part until the `@` sign. - `${env{DS_HEADER}{$value} fail}` looks up an environment variable by key `DS_HEADER`. This is usually defined in `docker-compose.yml`. The value must be the "secret" header value as defined in docspell's configuration file. - `${env{DS_URL}{$value} fail}` the url to docspell. It is looked up from the environment with key `DS_URL`, which is usually defined in `docker-compose.yml`. Adding the `$local_part` at the end means that mails to `somename@test.org` are uploaded to the collective `somename`. # Install with Docker Go into the `tools/exim` directory and build the docker image: ``` bash docker build -t ds-exim:latest -f exim.dockerfile . ``` Then start docspell somewhere and configure the integration endpoint to use http-header protection; i.e. set this in the config file: ``` bash docspell.server { integration-endpoint { enabled = true http-header = { enabled = true header-value = "test123" } } } ``` Then edit the `docker-compose.yml` and change the environment variables as needed. Finally start the container: ``` bash docker-compose up ``` # Test Run Now it is possible to send mails to this MTA which will be immediatly uploaded to docspell for the collective corresponding to the `$local_part` of the recipients address. Here is a quick telnet session (the collective is named `family`): ``` ~> telnet localhost 25 Trying ::1... Connected to localhost. Escape character is '^]'. 220 test.org ESMTP Exim 4.93 Sun, 14 Jun 2020 19:03:51 +0000 ehlo localhost 250-test.org Hello localhost [::1] 250-SIZE 31457280 250-8BITMIME 250-PIPELINING 250-CHUNKING 250 HELP mail from:<me@test.org> 250 OK rcpt to:<family@test.org> 250 Accepted data 354 Enter message, ending with "." on a line by itself From: me@test.org To: family@test.org Subject: This is a test Test, this is just a test mail. . 250 OK id=1jkXwf-000007-0d quit 221 test.org closing connection Connection closed by foreign host. ~> ``` The mail is processed and results in an item: {{ figure(file="exim-mail.png") }} However, if a mail is to an unknown collective or not to the configured local domain, the server rejects it immediately: ``` bash ~> telnet localhost 25 Trying ::1... Connected to localhost. Escape character is '^]'. 220 test.org ESMTP Exim 4.93 Sun, 14 Jun 2020 19:07:04 +0000 ehlo localhost 250-test.org Hello localhost [::1] 250-SIZE 31457280 250-8BITMIME 250-PIPELINING 250-CHUNKING 250 HELP mail from:<me@test.org> 250 OK rcpt to:<family22@test.org> 550 Recipient unknown rcpt to:<family@gmail.com> 550 Administrative prohibition quit 221 test.org closing connection Connection closed by foreign host. ~> ```