Billionmail/BillionMail · error

failed to update BILLIONMAIL_HOSTNAME in postfix container:

Error message

failed to update BILLIONMAIL_HOSTNAME in postfix container: %v

What it means

After updating .env, Add runs `sed` inside the Postfix container to replace the BILLIONMAIL_HOSTNAME line in /postfix.sh. This error wraps failure of the Docker exec (DockerApiFromCtx(...).ExecCommandByName on consts.SERVICES.Postfix). It means the Postfix container's hostname script could not be edited in-place.

Source

Thrown at core/internal/service/domains/domains.go:126

				Active:    1,
			})
		}

		// attempt update hostname in .env file
		hostname := public.MustGetDockerEnv("BILLIONMAIL_HOSTNAME", "")

		if hostname == "" || hostname == "mail.example.com" {
			err = public.SetDockerEnv("BILLIONMAIL_HOSTNAME", public.FormatMX(domain.Domain))

			if err != nil {
				return fmt.Errorf("failed to update BILLIONMAIL_HOSTNAME in .env file: %v", err)
			}

			// update postfix environment parameter
			_, err = public.DockerApiFromCtx(ctx).ExecCommandByName(ctx, consts.SERVICES.Postfix, []string{"bash", "-c", fmt.Sprintf("sed -i '/^BILLIONMAIL_HOSTNAME=/d' /postfix.sh && sed -i '/^#!\\/bin\\/bash/a BILLIONMAIL_HOSTNAME=%s' /postfix.sh", public.FormatMX(domain.Domain))}, "root")

			if err != nil {
				return fmt.Errorf("failed to update BILLIONMAIL_HOSTNAME in postfix container: %v", err)
			}

			// restart postfix service
			err = public.DockerApiFromCtx(ctx).RestartContainerByName(ctx, consts.SERVICES.Postfix)

			if err != nil {
				return fmt.Errorf("failed to restart postfix container: %v", err)
			}
		}

		// catchall
		if domain.Catchall != "" {
			err = setCatchall(ctx, domain.Domain, domain.Catchall)
		}
		return err
	}

	return err

View on GitHub (pinned to fc36c76c05)

Solutions

  1. Confirm the Postfix container is running: docker ps (name must match consts.SERVICES.Postfix)
  2. Check the wrapped error for 'no such container' vs exec exit code
  3. Verify /postfix.sh exists and contains the BILLIONMAIL_HOSTNAME line inside the container
  4. Set BILLIONMAIL_HOSTNAME via docker compose env and recreate the postfix container as a fallback

Example fix

// before
_, err = public.DockerApiFromCtx(ctx).ExecCommandByName(ctx, consts.SERVICES.Postfix, []string{"bash","-c", fmt.Sprintf("sed -i ...", ...)}, "root")
if err != nil { return fmt.Errorf("failed to update BILLIONMAIL_HOSTNAME in postfix container: %v", err) }
// after
_, err = public.DockerApiFromCtx(ctx).ExecCommandByName(ctx, consts.SERVICES.Postfix, []string{"bash","-c", sedCmd}, "root")
if err != nil {
    logger.Errorf(ctx, "postfix sed exec failed: %v", err)
    return fmt.Errorf("failed to update BILLIONMAIL_HOSTNAME in postfix container (is %s running?): %v", consts.SERVICES.Postfix, err)
}
Defensive patterns

Strategy: retry

Validate before calling

running, err := public.DockerApiFromCtx(ctx).IsContainerRunning(ctx, consts.SERVICES.Postfix)
if err != nil || !running { return fmt.Errorf("postfix container %s not running before exec", consts.SERVICES.Postfix) }

Try / catch

err := retry.Do(3, 2*time.Second, func() error {
    _, err := public.DockerApiFromCtx(ctx).ExecCommandByName(ctx, consts.SERVICES.Postfix, sedArgs, "root")
    return err
})
if err != nil { return fmt.Errorf("failed to update BILLIONMAIL_HOSTNAME in postfix container: %v", err) }

Prevention

When it happens

Trigger: AddDomain on the first/default-hostname domain when the docker exec fails: Postfix container not running, exec driver unavailable, /postfix.sh missing inside the container, or Docker socket/daemon errors.

Common situations: Postfix container stopped or crashed during setup; container name mismatch after stack rename; minimal image lacking sed; Docker daemon restarted mid-deployment.

Related errors


AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05). Data as JSON: /api/errors/f4ef71942e77343c. Report an issue: GitHub.