Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Attempted Reply/Send Failed from alias #192

Closed
spyesx opened this issue Nov 4, 2022 · 50 comments
Closed

Attempted Reply/Send Failed from alias #192

spyesx opened this issue Nov 4, 2022 · 50 comments

Comments

@spyesx
Copy link

spyesx commented Nov 4, 2022

Hi guys, I'm receiving the same email as anonaddy/anonaddy/issues/310 from my self-hosted instance.

Attempted Reply/Send Failed

An attempt to send or reply from your alias [...]

I just upgraded to the last docker image with Rspamd, I send emails from gmail to anonaddy in order to reply to an email received earlier. As far as I know, gmail has a proper dmarc record.

/etc/rspamd/local.d/milter_headers.conf is present in the container and looks correct.

rspamadm configdump -m result is:

Modules enabled: force_actions, forged_recipients, phishing, milter_headers, regexp, mime_types, once_received, history_redis, settings, arc, maillist, fuzzy_check, dkim_signing, dkim, whitelist, spf, rbl, dmarc, mid, multimap, greylist, hfilter, bayes_expiry, emails
Modules disabled (explicitly): metadata_exporter, neural, ratelimit, rspamd_update, spamtrap, aws_s3, dcc, asn, external_relay, bimi, replies, p0f, trie, http_headers, mx_check, chartable
Modules disabled (unconfigured): antivirus, fuzzy_check, elastic, url_redirector, reputation, clickhouse, spamassassin, metric_exporter, clustering, ip_score, dynamic_conf, maps_stats, fuzzy_collect, external_services
Modules disabled (no Redis):
Modules disabled (experimental):
Modules disabled (failed):

is there anything I can provide to help?

@spyesx
Copy link
Author

spyesx commented Nov 4, 2022

While reading gmail.com's DMARC carefully I found out the following:

dig TXT _dmarc.gmail.com +noall +answer

; <<>> DiG 9.10.6 <<>> TXT _dmarc.gmail.com +noall +answer
;; global options: +cmd
_dmarc.gmail.com.	111	IN	TXT	"v=DMARC1; p=none; sp=quarantine; rua=mailto:mailauth-reports@google.com"

Do you see p=none ?

Now read again the message from Anonaddy:

If this attempt was made by yourself, then you need to make sure your recipient's domain (gmail.com) has the correct DNS records in place; SPF, DKIM and DMARC.

If this attempt was not made by you, then someone else may be attempting to send a message from your alias. Make sure you have a suitable DMARC policy in place (with p=quarantine or p=reject) along with SPF and DKIM records to protect your recipient's email address from being spoofed.

See, p=none is not p=quarantine or p=reject. Is there a "strict" configuration to set somewhere?

@willbrowningme
Copy link
Member

It can be p=none, I just recommend quarantine or reject.

What does the notification email you receive say your authentication results are, or does it not contain them?

@spyesx
Copy link
Author

spyesx commented Nov 6, 2022

It can be p=none, I just recommend quarantine or reject.

We're not in control of Gmail's DMARC :) Or others... However, how can I test if it is that or not?

What does the notification email you receive say your authentication results are, or does it not contain them?

Screenshot 2022-11-06 at 11 40 25

Could it be an IPv6 issue like "kinda mentioned" in anonaddy/anonaddy#310 ?

@spyesx
Copy link
Author

spyesx commented Nov 6, 2022

Alright, there is a big problem with something inside this container. My eyes are turned to Rspamd but I couldn't test it.

After enabling IPv6 for Docker, suddenly we can send emails through Anonaddy.

What does it mean?

Well, it means that something in the container is using IPv6 only where it shouldn't.

  • Is there an IPv6 hardcoded somewhere?
  • Is there a bad implementation of DNS queries somewhere? Ex: By getting the first IP of a resolver (not standard) instead of a round robin (standard).

This is a important issue because yes, we should use IPv6 today but, we should not have IPv6 only.

I will post this message in anonaddy/anonaddy's project as I am not sure that issue comes from Rspamd.

For those who'd need a quick get around like me until this issue is fixed, here is how I've activated IPv6 for Docker.

Update /etc/docker/daemon.json with the following lines (Yes we need to NAT IPv6, no we don't need to provide a gateway):

{
  "ipv6": true,
  "fixed-cidr-v6": "fd01::/64",
  "ip6tables": true
}

Restart docker:

systemctl restart docker

For those using Traefik, you'll need to create a network for Traefik with IPv6 enabled:

docker network create --ipv6 --subnet=fd01:1::/64 traefik

@klibansky
Copy link

Hi All, have had this problem and couldn't seem to figure it out for a while but I just fixed it and it works perfectly now with multiple domain names. The errors I was getting were not very helpful, but in the end it's pretty simple at least for me it was.

I was getting the exact same email as above.

It all came down to the SPF DNS record.
You have to add the include part and add the domain/host of your anonaddy server/instance. You have to add this record for every domain that to are forwarding TO and you want to reply FROM.

DNS TXT RECORD

NAME
domain-to.com.

VALUE
v=spf1 a mx ptr a:forward.com a:mail.forward.com include:forward.com include:mail.forward.com ~all

Where domain-to.com = the domain name you are forwarding to and you want to reply from & forward.com is the domain/host name which is hosting the anonaddy instance and aliasses.

You should always already ave an spf record with you are telling it that not only the mx host is allowed to send email, but also your anonaddy server.

Hope it helps.

@spyesx
Copy link
Author

spyesx commented Nov 23, 2022

Question is, how should people do with mail services providers such as GMail, Outlook...? They can't modify an SPF record on a zone they don't own.

@Zegorax
Copy link
Contributor

Zegorax commented Jan 17, 2023

I have tried both methods, IPv6 and adding the special SPF record. None of them worked. Is there a clear indication about what is the exact issue originating from this error message ?

@spyesx
Copy link
Author

spyesx commented Jan 17, 2023

@Zegorax

  • which domain do you send an email to (when you send an email it has to be the SPF of the receiver, not yours) ?
  • do you confirm having IPv6 enabled and working in your container?
  • do you confirm that your container can send a request to you DNS server using IPv6?

@Zegorax
Copy link
Contributor

Zegorax commented Jan 17, 2023

@spyesx I need to check again about IPv6, something seems to be not working right on my system.

Would you like to share an obfuscated SPF, DMARC and TXT records you have for your domain ?

@spyesx
Copy link
Author

spyesx commented Jan 17, 2023

My SPF or DMARC won't be useful since you're not sending an email to or from my domain :)

Open a shell in your container then get a random IPv6, let's say Gmail

$ dig +short AAAA gmail.com
2a00:1450:4002:411::2005

From here you can ping this IPv6:

ping -6 2a00:1450:4002:411::2005
PING 2a00:1450:4002:411::2005(2a00:1450:4002:411::2005) 56 data bytes
64 bytes from 2a00:1450:4002:411::2005: icmp_seq=1 ttl=114 time=19.9 ms
64 bytes from 2a00:1450:4002:411::2005: icmp_seq=2 ttl=114 time=19.9 ms

If you can't ping, your container is not IPv6 ready.

Therefore, when Rspamd (as I assume still now) will send a query to a DNS server to get the SPF record but it won't get any answer because it uses IPv6 only. This is the bug. If your container is not IPv6 ready... you won't go further.

@Zegorax
Copy link
Contributor

Zegorax commented Jan 17, 2023

Okay now I get it. So it's more on Rspamd's side and it has an issue trying to do IPv6-only. My containers are definitely not ready for IPv6 since I do not use it yet on the host system.

I firstly assumed that Rspamd needed to have an IPv6 address binded for it to work, but that it would not actively use it, which is not the case then here.

I will need to search deeper on how to work around this problem.

@Zegorax
Copy link
Contributor

Zegorax commented Jan 17, 2023

@spyesx I searched this repo and came across https://github.com/anonaddy/docker/blob/master/examples/rspamd/anonaddy.env By default, RSPAMD_ENABLE is not set. I checked in the container and there is no process running related to rspamd as well.

Therefore, I think the problem does not come from rspamd with/without IPv6.

Do you have RSPAMD_ENABLE set to "true"?

@GitTworn
Copy link

First of all add this line to your .env file. It resolved multiple problems for me (replace with your domain names):
SANCTUM_STATEFUL_DOMAINS=localhost,localhost:8112,127.0.0.1,127.0.0.1:8112,::1,mail.domain.com,mil.domain.com:8112

I do have RSPAMD_ENABLE enabled and it works.

Have you generated the DKIM key and added it to your DNS record?

@Zegorax
Copy link
Contributor

Zegorax commented Jan 18, 2023

@GitTworn DKIM is enabled and active.

I've looked at SANCTUM_STATEFUL_DOMAINS, but to be honest, it should not change anything since from what I understood, this variable controls something that is more likely related to Laravel's authentication mechanism.

I tried it but as expected it did not change anything unfortunately.

@GitTworn
Copy link

GitTworn commented Jan 18, 2023

These are my templates and my install works great.
I almost died getting to this point but I'm happy to share.

I might state the obvious but...:
First you need a domain name. For this example i'm using domain.com.

In the DNS settings of that domain add an A record for the mail subdomain to the IP of your server.
I also add a * (wild card) to the same server because I host more subdomains on the same server.

Now add an MX record to the mail subdomain with priority 10.
Also add a TXT record _dmarc to v=DMARC1;p=quarantine;pct=90;sp=quarantine;adkim=r;aspf=r
and a TXT for domain.com. to v=spf1 mx ~all

Adjust the file system paths as you like in the following;

I like using Nginx Reverse Proxy Manager because it has a nice UI.

In docker first create a docker network named: reverseproxy-nw for connecting the internal docker images so we dont have to expose ports to the outside world.

Then run:

Nginx Proxy Manager - compose file

services:
  nginx-proxy-manager:
    image: jlesage/nginx-proxy-manager
    container_name: nginx-proxy-manager
    ports:
      - "80:8080"
      - "443:4443"
      - "8181:8181" # open now, close later
    volumes:
      - "/root/docker/nginx-proxy-manager:/config:rw"
    environment:
      - "TZ=Europe/Belfast"
    restart: always
    networks:
      - nginx-proxy-manager-nw
      - reverseproxy-nw

networks:
  nginx-proxy-manager-nw:
  reverseproxy-nw:
    external: true

Then create a docker .env file in the correct location for anonaddy:

anonaddy.env file

TZ=Europe/Belfast
PUID=1000
PGID=1000

MEMORY_LIMIT=512M
UPLOAD_MAX_SIZE=50M
OPCACHE_MEM_SIZE=128
REAL_IP_FROM=0.0.0.0/32
REAL_IP_HEADER=X-Forwarded-For
LOG_IP_VAR=http_x_forwarded_for

APP_KEY=base64:QEgJ4hBcuQugQCtKIyHZo/B7HvIVqomXFpAtpKOfKKk=
APP_DEBUG=true
APP_URL=https://mail.domain.com

ANONADDY_RETURN_PATH=bounces@domain.com
ANONADDY_ADMIN_USERNAME=something
ANONADDY_ENABLE_REGISTRATION=false
ANONADDY_DOMAIN=domain.com
ANONADDY_ALL_DOMAINS=domain.com
ANONADDY_HOSTNAME=mail.domain.com
ANONADDY_DNS_RESOLVER=1.1.1.1
ANONADDY_SECRET=alksjhU930ufaakljfkljashdflkjsahdfjkladhfjlkah245g
ANONADDY_LIMIT=200
ANONADDY_BANDWIDTH_LIMIT=10737418240
ANONADDY_NEW_ALIAS_LIMIT=1000
ANONADDY_ADDITIONAL_USERNAME_LIMIT=100
ANONADDY_WORDLIST_FILE=/var/www/anonaddy/config/wordlist.json

# IMPORTANT (need this)
SANCTUM_STATEFUL_DOMAINS=localhost,localhost:8112,127.0.0.1,127.0.0.1:8112,::1,mail.domain.com,mil.domain.com:8112

MAIL_FROM_NAME=name
MAIL_FROM_ADDRESS=noreply@domain.com

POSTFIX_DEBUG=false
POSTFIX_SMTPD_TLS=false
POSTFIX_SMTP_TLS=false
POSTFIX_SMTPD_TLS_CERT_FILE=/certs/certificate.pem
POSTFIX_SMTPD_TLS_KEY_FILE=/certs/privatekey.pem
# because my host doesn't allow me to open port 25, I use a  different smtp server to relay the email. You can use any server you can log in to.
POSTFIX_RELAYHOST=smtp.mail.server
POSTFIX_RELAYHOST_AUTH_ENABLE=true
POSTFIX_RELAYHOST_USERNAME=username-mail-server
POSTFIX_RELAYHOST_PASSWORD=password-to-log-in-to-mail-server

DKIM_ENABLE=true
DMARC_ENABLE=true

RSPAMD_ENABLE=true
RSPAMD_WEB_PASSWORD=you-can-choose

Anonaddy compose file
You have to manually add the variables and values forMYSQL_DATABASE, MYSQL_USER, and MYSQL_PASSWORD. It won't work via the env file.

services:
  anonaddy_db:
    image: mariadb:10.8
    container_name: anonaddy_db
    command:
      - "mysqld"
      - "--character-set-server=utf8mb4"
      - "--collation-server=utf8mb4_unicode_ci"
    volumes:
      - "/root/docker/anonaddy/db:/var/lib/mysql"
    environment:
      - "MYSQL_ALLOW_EMPTY_PASSWORD=yes"
      - "MYSQL_DATABASE"
      - "MYSQL_USER"
      - "MYSQL_PASSWORD"
    restart: always
    networks:
      - reverseproxy-nw
  anonaddy_redis:
    image: redis:4.0-alpine
    container_name: anonaddy_redis
    restart: always
    networks:
      - reverseproxy-nw
  anonaddy:
    image: anonaddy/anonaddy:latest
    container_name: anonaddy
    depends_on:
      - anonaddy_db
      - anonaddy_redis
    ports:
      - target: 25
        published: 25
        protocol: tcp
      - target: 11334
        published: 11334
        protocol: tcp
      - target: 587
        published: 587
        protocol: tcp
    volumes:
      - "/root/docker/anonaddy/data:/data"
    env_file:
      - "./anonaddy.env"
    environment:
      - "DB_HOST=anonaddy_db"
      - "DB_DATABASE=${MYSQL_DATABASE}"
      - "DB_USERNAME=${MYSQL_USER}"
      - "DB_PASSWORD=${MYSQL_PASSWORD}"
      - "REDIS_HOST=anonaddy_redis"
    restart: always
    networks:
      - reverseproxy-nw

networks:
  reverseproxy-nw:
    external: true

Create User

Log into a terminal of the anonaddy docker image and type: anonaddy anonaddy:create-user "username" "your@email.com".

After that stay in the console and type: anonaddy gen-dkim
Some files will be generated containing a key.

DNS

Now edit your domain name DNS settings and add a TXT record for default._domainkey with value v=DKIM1; k=rsa; p=[KEY]
where [KEY] = the long string that is generated in the step above.

Now first open port 8181 on your firewall to allow access to the reverse proxy manager UI. We are going to close it later. Also open the anonaddy email ports you need: 25/tcp, 11334/tcp, 587/tcp.
I open 587 because my host does not allow me to send email, so I use another server.

Now log in to domain.com:8181 to log into Nginx Reverse Proxy Manager UI (google credentials). Change your password and create a reverse proxy host (revprox.domain.com) to point to the reverse proxy manager docker image: http://nginx-proxy-manager:8181. Make sure to generate a new ssl certificate.

You can now close port 8181 on the firewall and log back in to the reverse proxy manager UI via the domain name https://revprox.domain.com.
You can also remove the 8181 port in the docker compose file and restart the image to un-expose the port.

Add a reverse proxy host for mail.domain.com to internal http://anonaddy:8000. You don't have to expose the anonaddy app port because you can use its internal host name, And internally all ports are always exposed.
Now you can log into the anonaddy app via the domain name and user you created, https://mail.domain.com and start creating aliases.

Now you can send emails to you aliases and they will get forwarded.

reply

If you want to reply from an email address that you are forwarding to, lets say you are forwarding to hello@john.com, you need to be able to edit the DNA settings of the domain john.com in order to allow the mail server (DNS MX record of john.com) to send/relay email using the mail server of domain.com (the mail server sending email for anonaddy). Because usually the mail server of the own domain john.com would be sending the email.

You do that by editing a TXT record for john.com by using the 'include' parameter.
The TXT record should look like this for the primary domain name, so john.com. with value v=spf1 a mx ptr a:domain.com a:mail.domain.com include:_spf.google.com include:domain.com include:mail.domain.com ~all

I'm replying from, and forwarding my aliases to, a google managed account using my own domain name.

This is what works for me...

@Twilek-de
Copy link

Hi all,
I have just installed anonaddy and I am seeing the same problem. Is there a solution on the horizon. My docker network does not support IPv6 and I am anxious to recreate it, as it is used by a large traefik installation. Is there a way to get this working without IPv6 or can I modify an existing docker network to support IPv6 (and would that help)?

@GitTworn
Copy link

I have IPv6 disabled system wide. It was bugging with my Docker install. AnonAddy does not depend on IPv6.

@Twilek-de
Copy link

I have IPv6 disabled system wide. It was bugging with my Docker install. AnonAddy does not depend on IPv6.

Hmm, ok my docker install has run everything else just fine up until now, what did you exactly change with your docker to get anondaddy to run proberly?

@GitTworn
Copy link

My exact steps are outlined above.

@Twilek-de
Copy link

That very much looks like my setup. The only thing I haven´t done like that is the SPF setup of the target domain to include the anondaddy domain....

@GitTworn
Copy link

What part is not 'running properly' in your case?

@Twilek-de
Copy link

When I try to reply to a anonaddy mail I get the "Attempted reply/send from alias has failed" error mail saying that my target domain must have a valid DMARC entry (which it has) and must permit the message to be sent (which I am just trying to find out wether the problem might be there).

@Twilek-de
Copy link

The targets DMARC is v=DMARC1; p=quarantine; rua=mailto:postmaster@xxx.de; ruf=mailto:postmaster@xxx.de; adkim=r; aspf=r; pct=100; rf=afrf; ri=86400; sp=none
What do I have to add to allow anonaddy mails to be sent?

@GitTworn
Copy link

For me this was fixed with the last section of my "guide";

You do that by editing a TXT record for john.com by using the 'include' parameter.
The TXT record should look like this for the primary domain name, so john.com. with value v=spf1 a mx ptr a:domain.com a:mail.domain.com include:_spf.google.com include:domain.com include:mail.domain.com ~all

@Twilek-de
Copy link

I changed that, but that did not do it for me.

@GitTworn
Copy link

Just remember that, because these are DNS settings, they might take a while to propagate.

@Twilek-de
Copy link

I will wait some more, Maybe it will start working...

@Twilek-de
Copy link

Ehm, I think there is a problem with DNS in my install. It seems it cannot read the TXT entry for a custom domain. I am using the stock docker image and DNS inside it works. I have set google dns as resolver and checked that google DNS sees the TXT entry. It does but anonaddy doesn´t....

@GitTworn
Copy link

Outgoing firewall? My hosting provider blocked port 25 for example. I'm using a relay SMTP server. It has nothing to do with DNS I know.

@Twilek-de
Copy link

Seemed to be the DNS caching. That now worked...

@GitTworn
Copy link

😀 that helps!

@Zegorax
Copy link
Contributor

Zegorax commented Feb 23, 2023

@GitTworn Can you make an example with the following data ?
Main email address is : test@maindomain.com
Anonaddy custom domain is : hiddendomain.com

Could you share what records should be for both domains ? (Maindomain.com and hiddendomain.com)

Thanks a lot in advance. I still cannot get it to work.

@Twilek-de
Copy link

Twilek-de commented Feb 24, 2023

Maybe I am on to something. When I try to add custom domains it first complains that it does not find an MX record. After some time when the DNS info is propagated properly it will start complaining that there is no SPF record (so it did find the MX records all right) and that never stops. This happend for two domains now although I copy and pasted the SPF info from the custom domains page. Maybe the whole problem is that it cannot parse SPF info correctly for some reason. That would also explain that the alias thing fails as it would not be able to parse the SPF info of the target domain and error out...

The TXT DNS for my domain reads:

;; ANSWER SECTION:
redacted.de. 86400 IN TXT "v=spf1 mx -all"

@rehanone
Copy link
Contributor

I have been struggling with this issue for a day and I think I finally got it working. This is my anonaddy.env file:

TZ=Etc/UTC
PUID=1000
PGID=1000

APP_NAME=AppAddy
APP_ENV=production
APP_KEY=secret
APP_DEBUG=false
APP_LOG_LEVEL=debug
# The URL of the AnonAddy instance, can be anything you like e.g. https://aa.example.com, or just https://example.com, if using a non-standard port you must include it e.g. https://example.test:8000. Do not include a trailing slash '/'
APP_URL=https://app.example.com

LOG_CHANNEL=stack

DB_CONNECTION=mysql

# The from name to be used for outgoing email notifications from AnonAddy
MAIL_FROM_NAME=Rehan
# The from address to be used for outgoing email notifications from AnonAddy
MAIL_FROM_ADDRESS=mailer@example.com
MAIL_DRIVER=smtp
MAIL_HOST=mail.example.com
MAIL_PORT=25
MAIL_ENCRYPTION=tls
MAIL_EHLO_DOMAIN=mail.example.com
MAIL_VERIFY_PEER=true

# The SMTP FROM address to be used if the alias address cannot be, e.g. for a custom domain that is not verified for sending
ANONADDY_RETURN_PATH=bounces@example.com
# This allows you to receive emails as a catch-all at the apex domain e.g. *@example.com
ANONADDY_ADMIN_USERNAME=johndoe
ANONADDY_ENABLE_REGISTRATION=false
ANONADDY_DOMAIN=example.com
ANONADDY_HOSTNAME=mail.example.com
ANONADDY_DNS_RESOLVER=1.1.1.1
ANONADDY_ALL_DOMAINS=example.com
# Used for verifying custom domains, can be anything e.g. 64U64QcpgWHAZPyr4nN58kDGvwj9TkKMGyuXcjMFA7CdhTDy2f
#ANONADDY_SECRET=long-random-string
# Number of emails that can be forwarded through the service per hour by any one user
ANONADDY_LIMIT=200
# Monthly bandwidth limit, default 100MB
ANONADDY_BANDWIDTH_LIMIT=104857600
# Limit on how many new aliases can be created per hour, default 100
ANONADDY_NEW_ALIAS_LIMIT=100
# Limit on the number of additional usernames that can be added, default 10
ANONADDY_ADDITIONAL_USERNAME_LIMIT=10
# Fingerprint of the private key that you generated on the server to be used to sign encrypted forwarded emails
#ANONADDY_SIGNING_KEY_FINGERPRINT=
# This is only needed if you will be adding any custom domains. If you do not need it then leave it blank. ANONADDY_DKIM_SIGNING_KEY=/etc/opendkim/keys/example.com/default.private
#ANONADDY_DKIM_SIGNING_KEY=
#ANONADDY_DKIM_SELECTOR=default

SANCTUM_STATEFUL_DOMAINS=app.example.com


# Postfix
POSTFIX_DEBUG=false
POSTFIX_SMTPD_TLS=true
POSTFIX_SMTPD_TLS_CERT_FILE=/certs/example.com.fullchain.pem
POSTFIX_SMTPD_TLS_KEY_FILE=/certs/example.com.key.pem
POSTFIX_SMTP_TLS=true

# Rspmod
RSPAMD_ENABLE=true
RSPAMD_WEB_PASSWORD=abc

I am not using the relay host and sending the emails directly from my IP. The current DNS setting I am using is:

SPF

example.com.		300	IN	TXT	"v=spf1 mx -all"

DKIM

default._domainkey.example.com. 300 IN	TXT	"v=DKIM1; k=rsa; p=PUBLIC_KEY"

DMARC

_dmarc.example.com.	300	IN	TXT	"v=DMARC1; p=reject; adkim=s; aspf=s"

This is my compose.yaml file:

---
version: '3.8'

secrets:
  mariadb_root:
    file: /docker-data/anonaddy/secrets/mariadb_root
  mariadb:
    file: /docker-data/anonaddy/secrets/mariadb
  app_key:
    file: /docker-data/anonaddy/secrets/app_key
  anonaddy_secret:
    file: /docker-data/anonaddy/secrets/anonaddy_secret
  postfix_relayhost_password:
    file: /docker-data/anonaddy/secrets/postfix_relayhost_password
  cloudflare_api_token:
    file: /docker-data/anonaddy/secrets/cloudflare_api_token
  rspamd_password:
    file: /docker-data/anonaddy/secrets/rspamd_password

networks:
  inner-net:
    driver: bridge
  backplain:
    external: true

services:
  db:
    image: mariadb:${DB_VERSION}
    container_name: 'anonaddy-db'
    command:
      - "mysqld"
      - "--character-set-server=utf8mb4"
      - "--collation-server=utf8mb4_unicode_ci"
    secrets:
      - mariadb_root
      - mariadb
    networks:
      - inner-net
    environment:
      MARIADB_ROOT_PASSWORD_FILE: /run/secrets/mariadb_root
      MARIADB_DATABASE: ${MARIADB_DATABASE}
      MARIADB_USER: ${MARIADB_USER}
      MARIADB_PASSWORD_FILE: /run/secrets/mariadb
    volumes:
      - type: bind
        source: /docker-data/anonaddy/mariadb
        target: /var/lib/mysql
        read_only: false
    healthcheck:
      test: ["CMD", "/usr/local/bin/healthcheck.sh", "--connect"]
      interval: 5s
      timeout: 5s
      retries: 10
      start_period: 10s
    restart: 'unless-stopped'

  redis:
    image: redis:alpine
    container_name: 'anonaddy-redis'
    networks:
      - inner-net
    environment:
      TZ: Etc/UTC
    volumes:
      - type: bind
        source: /docker-data/anonaddy/redis
        target: /data
        read_only: false
    healthcheck:
      test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
      interval: 1s
      timeout: 3s
      retries: 10
      start_period: 2s
    restart: 'unless-stopped'

  cert-manager:
    image: rehanone/auto-cert-manager:${CERT_MANAGER_VERSION}
    container_name: 'anonaddy-cert-manager'
    secrets:
      - cloudflare_api_token
    environment:
      DOMAINS: example.com,*.example.com
      EMAIL: ${CERT_MANAGER_EMAIL}
      CERTBOT_PLUGIN: ${CERT_MANAGER_CERTBOT_PLUGIN}
      CLOUDFLARE_API_TOKEN_FILE: /run/secrets/cloudflare_api_token
      PROPAGATION_SECONDS: ${CERT_MANAGER_PROPAGATION_SECONDS}
      DEBUG: true
      STAGING: ${CERT_MANAGER_STAGING}
    volumes:
      - type: bind
        source: /docker-data/anonaddy/tls/letsencrypt
        target: /etc/letsencrypt
        read_only: false
      - type: bind
        source: /docker-data/anonaddy/tls/certs
        target: /certs
        read_only: false
      - type: bind
        source: /docker-data/anonaddy/tls/log
        target: /var/log/letsencrypt
        read_only: false
    restart: 'unless-stopped'

  app:
    image: anonaddy/anonaddy:${APP_VERSION}
    container_name: 'anonaddy-app'
    labels:
      - traefik.enable=true
      - traefik.http.routers.anonaddy-app.rule=Host(`app.example.com`)
      - traefik.http.routers.anonaddy-app.entrypoints=websecure
      - traefik.http.routers.anonaddy-app.tls=true
      - traefik.http.routers.anonaddy-app.tls.certresolver=le-resolver
      - traefik.http.routers.anonaddy-app.middlewares=security-headers@file
      - traefik.http.routers.anonaddy-app.service=anonaddy-app
      - traefik.http.services.anonaddy-app.loadbalancer.server.scheme=http
      - traefik.http.services.anonaddy-app.loadbalancer.server.port=8000
      - traefik.http.routers.anonaddy-rspamd.rule=Host(`rspamd-admin.example.com`)
      - traefik.http.routers.anonaddy-rspamd.entrypoints=websecure
      - traefik.http.routers.anonaddy-rspamd.tls=true
      - traefik.http.routers.anonaddy-rspamd.tls.certresolver=le-resolver
      - traefik.http.routers.anonaddy-rspamd.middlewares=security-headers@file
      - traefik.http.routers.anonaddy-rspamd.service=anonaddy-rspamd
      - traefik.http.services.anonaddy-rspamd.loadbalancer.server.scheme=http
      - traefik.http.services.anonaddy-rspamd.loadbalancer.server.port=11334
    secrets:
      - mariadb
      - app_key
      - anonaddy_secret
      - postfix_relayhost_password
      - rspamd_password
    networks:
      - inner-net
      - backplain
    environment:
      DB_HOST: db
      DB_DATABASE: ${MARIADB_DATABASE}
      DB_USERNAME: ${MARIADB_USER}
      DB_PASSWORD_FILE: /run/secrets/mariadb
      REDIS_HOST: redis
      APP_KEY_FILE: /run/secrets/app_key
      ANONADDY_SECRET_FILE: /run/secrets/anonaddy_secret
      POSTFIX_RELAYHOST_PASSWORD_FILE: /run/secrets/postfix_relayhost_password
      RSPAMD_WEB_PASSWORD_FILE: /run/secrets/rspamd_password
    volumes:
      - type: bind
        source: /docker-data/anonaddy/tls/certs
        target: /certs
        read_only: true
      - type: bind
        source: /docker-data/anonaddy/app-data
        target: /data
        read_only: false
    env_file:
      - ./anonaddy.env
    ports:
      - "25:25/tcp"
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy
    restart: 'unless-stopped'

The .env file

APP_VERSION=latest

# DB Section
DB_VERSION=10.5
MARIADB_DATABASE=anonaddy
MARIADB_USER=anonaddy

CERT_MANAGER_VERSION=latest
CERT_MANAGER_PROPAGATION_SECONDS=220
CERT_MANAGER_STAGING=false
CERT_MANAGER_EMAIL="someone@sombody.com"
CERT_MANAGER_CERTBOT_PLUGIN=cloudflare

I did not make any other changes that are related to IPv6. I hope this will be helpful for others trying to setup using this docker image. I am using traefik in a separate container but I left the labels in there just as a example. You can safely remove it.

@Twilek-de
Copy link

Hmmm now it has stopped complaining that the SPF is not there but that the CNAME domainkey record is not found (which of course is there). Something seems to go terribly wrong with DNS querying...

@GitTworn
Copy link

On my side it is working great. It definitely has to do with DNS. I was tinkering with it for days until it worked. The documentation is not great (verbose enough) on that point.

@rehanone
Copy link
Contributor

Hmmm now it has stopped complaining that the SPF is not there but that the CNAME domainkey record is not found (which of course is there). Something seems to go terribly wrong with DNS querying...

It could just be a case of DNS caching. Remember, it could take up to 24 hours for full propagation of DNS changes.

@Twilek-de
Copy link

Hmmm now it has stopped complaining that the SPF is not there but that the CNAME domainkey record is not found (which of course is there). Something seems to go terribly wrong with DNS querying...

It could just be a case of DNS caching. Remember, it could take up to 24 hours for full propagation of DNS changes.

Yes indeed, but suddenly it recognizes the SPF Records but not the CNAME which I setup at the same time. Don´t know what the problem is there and it does not explain the alias send fail.

@Twilek-de
Copy link

Something is broken the way anonaddy handles DNS queries. It will not find the CNAME entry for my custom domain althought it´s definitely set right. Is there some log file with detailed information? The Log File of the Docker Container does not tell me much.

@Twilek-de
Copy link

I found the logs (feeling stupid for missing them in storage). I get an "error":"dns_get_record(): DNS Query failed".

@Zegorax
Copy link
Contributor

Zegorax commented Apr 21, 2023

Has anyone a fix for that now ? I spend 4 hours yesterday trying to fix it but I cannot find what is going wrong

@Twilek-de
Copy link

I wasn´t able to fix it and finally switched to simplelogin, which was a bit of a pain to setup but now works flawlessly.

@Zegorax
Copy link
Contributor

Zegorax commented Apr 21, 2023

@crazy-max May I ask you to please check this issue a bit ? We really don't know what could be wrong with our configurations.

@Zegorax
Copy link
Contributor

Zegorax commented Apr 21, 2023

Hello guys!

I spent a few hours today trying to dig the issue and I finally understood why it was not working.

Root cause

As defined in https://github.com/anonaddy/anonaddy/blob/ad77a6ccf90a974408370df9e574356ff2a04fef/app/Console/Commands/ReceiveEmail.php#L156 , AnonAddy checks whether the headers X-AnonAddy-Spam or X-AnonAddy-Dmarc-Allow are present or not.
Those headers are added ONLY if Rspamd is enabled and correctly configured to inject those headers, which is not the case here because the environment variable RSPAMD_ENABLE is set to false by default.

Second problem

Even after enabled Rspamd, the messages would still not get delivered. I then explored the Rspamd dashboard to understand why. After seeing the messages, they would not have the DMARC_POLICY_ALLOW tag attached to them. As per the default Rspamd config in this repo, the header X-AnonAddy-Dmarc-Allow will only get injected if DMARC_POLICY_ALLOW is added.

After setting the Rspamd logs to a more verbose option, I figured out that since I'm running my mailserver also in containers, they are (obviously) in a local network which Rspamd does not like by default.
Because, by default, Rspamd will skip DKIM, DMARC and SPF checks if a new message comes from a local network. This behavior is defined in /etc/rspamd/options.inc. I therefore removed the content of the local_addrs variable defined there.

I tried again, and eureka, it works! So, TL;DR:

Solution

Update your docker-compose as the following:

entrypoint: bash -c "sed -i 's/local_addrs.*$$/local_addrs=[]/' /etc/rspamd/options.inc && /init"

...
environment:
    - "RSPAMD_ENABLE=true"

I will create a PR in the following days to fix the issue.

@rehanone
Copy link
Contributor

@Zegorax , Thanks for investigating this issue and providing such a detailed analysis! Cannot wait to see the fix applied in a PR.

@Zegorax
Copy link
Contributor

Zegorax commented Apr 21, 2023

Pull request has been created in #207. It will need an approval from the maintainers.

@spyesx
Copy link
Author

spyesx commented Jul 6, 2023

😞 I just upgraded to the last version of this image. We can't send or reply from any alias anymore.

It was working well for me since #192 (comment)

The DMARC record did not change for ages but let's control it:

~ dig +short TXT _dmarc.DOMAIN.TLD
"v=DMARC1; p=quarantine; adkim=s"

The DMARC record looks correct to me.

Tracing the issue leads me here too: https://github.com/anonaddy/anonaddy/blob/master/app/Console/Commands/ReceiveEmail.php#L156

if ($verifiedRecipient?->can_reply_send) {
    // Check if the Dmarc allow or spam headers are present from Rspamd
    if (! $this->parser->getHeader('X-AnonAddy-Dmarc-Allow') || $this->parser->getHeader('X-AnonAddy-Spam')) {
        // Notify user and exit
        $verifiedRecipient->notify(new SpamReplySendAttempt($recipient, $this->senderFrom, $this->parser->getHeader('X-AnonAddy-Authentication-Results')));

        exit(0);
    }

So I simply trace the variables:

Log::info([
  'can_reply_send' => $verifiedRecipient?->can_reply_send,
  'X-AnonAddy-Dmarc-Allow' => $this->parser->getHeader('X-AnonAddy-Dmarc-Allow'),
  'X-AnonAddy-Spam' => $this->parser->getHeader('X-AnonAddy-Spam'),
  'In-Reply-To' => $this->parser->getHeader('In-Reply-To')
]);

I tried with the following configurations (removing and creating all containers each time):

  1. RSPAMD_ENABLE=false
    cat /etc/rspamd/options.inc | grep local_addrs
    cat: /etc/rspamd/options.inc: No such file or directory
     [2023-07-06 08:18:12] production.INFO: array (
       'can_reply_send' => true,
       'X-AnonAddy-Dmarc-Allow' => false,
       'X-AnonAddy-Spam' => false,
       'In-Reply-To' => false,
     )
  2. RSPAMD_ENABLE=true
    RSPAMD_NO_LOCAL_ADDRS=true
    cat /etc/rspamd/options.inc | grep local_addrs
    local_addrs = [];
     [2023-07-06 08:22:03] production.INFO: array (
       'can_reply_send' => true,
       'X-AnonAddy-Dmarc-Allow' => false,
       'X-AnonAddy-Spam' => false,
       'In-Reply-To' => false,
     )
  3. RSPAMD_ENABLE=true
    RSPAMD_NO_LOCAL_ADDRS=false
    cat /etc/rspamd/options.inc | grep local_addrs
    local_addrs = [192.168.0.0/16, 10.0.0.0/8, 172.16.0.0/12, fd00::/8, 169.254.0.0/16, fe80::/10];
     [2023-07-06 08:24:14] production.INFO: array (
       'can_reply_send' => true,
       'X-AnonAddy-Dmarc-Allow' => false,
       'X-AnonAddy-Spam' => false,
       'In-Reply-To' => false,
     )

So now, Rspamd or not... we can't send emails anymore?

Captain? An idea? 😛

@spyesx
Copy link
Author

spyesx commented Jul 6, 2023

Alright... finally found out that the milter's configuration is missing. Even when RSPAMD_ENABLE=true.

I added it in a custom Postfix conf, following the doc to Override Postfix main configuration.

+milter_default_action = accept
+smtpd_milters = inet:127.0.0.1:11332
+non_smtpd_milters = $smtpd_milters
+milter_mail_macros =  i {mail_addr} {client_addr} {client_name} {auth_authen}

Now it works but a question remains. I didn't dive into the code enough to answer. If the configuration allows a RSPAMD_ENABLE=false, then how will Anonaddy get the headers it expects?

@crazy-max
Copy link
Member

#207 should fix this issue by setting RSPAMD_NO_LOCAL_ADDRS=true env var.

@Lexxior
Copy link

Lexxior commented Jul 28, 2023

#207 should fix this issue by setting RSPAMD_NO_LOCAL_ADDRS=true env var.

Even when I set that env, it still doesn't work for me
Do I have to configure anything else?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants