mirror of
https://github.com/wneessen/go-mail.git
synced 2024-11-25 23:15:08 +01:00
Compare commits
19 commits
3a3eaed348
...
d7b32480fd
Author | SHA1 | Date | |
---|---|---|---|
d7b32480fd | |||
23399ed84c | |||
90e3162a22 | |||
273a26ca53 | |||
a815c58571 | |||
c33900ca29 | |||
4b8bf0507d | |||
9072aef355 | |||
3aef85e324 | |||
f82ac0c5ae | |||
eeccee0d94 | |||
9c57ba56cf | |||
4d4aa1e1df | |||
960c015a93 | |||
12e9a0cb5d | |||
9e6c1f0417 | |||
0e9646e0e4 | |||
c47f08dc7f | |||
|
87c0575dd4 |
12 changed files with 475 additions and 359 deletions
195
.github/workflows/ci.yml
vendored
Normal file
195
.github/workflows/ci.yml
vendored
Normal file
|
@ -0,0 +1,195 @@
|
||||||
|
# SPDX-FileCopyrightText: 2024 The go-mail Authors
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
name: CI
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref_name }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
codecov:
|
||||||
|
name: Test with Codecov coverage (${{ matrix.os }} / ${{ matrix.go }})
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
concurrency:
|
||||||
|
group: ci-codecov-${{ matrix.os }}-${{ matrix.go }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest]
|
||||||
|
go: ['1.23']
|
||||||
|
env:
|
||||||
|
PERFORM_ONLINE_TEST: ${{ vars.PERFORM_ONLINE_TEST }}
|
||||||
|
TEST_SENDMAIL: ${{ vars.TEST_SENDMAIL }}
|
||||||
|
TEST_HOST: ${{ secrets.TEST_HOST }}
|
||||||
|
TEST_USER: ${{ secrets.TEST_USER }}
|
||||||
|
TEST_PASS: ${{ secrets.TEST_PASS }}
|
||||||
|
steps:
|
||||||
|
- name: Harden Runner
|
||||||
|
uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
|
||||||
|
with:
|
||||||
|
egress-policy: audit
|
||||||
|
- name: Checkout Code
|
||||||
|
uses: actions/checkout@61b9e3751b92087fd0b06925ba6dd6314e06f089 # master
|
||||||
|
- name: Setup go
|
||||||
|
uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0
|
||||||
|
with:
|
||||||
|
go-version: ${{ matrix.go }}
|
||||||
|
check-latest: true
|
||||||
|
- name: Install sendmail
|
||||||
|
run: |
|
||||||
|
sudo apt-get -y update >/dev/null && sudo apt-get -y upgrade >/dev/null && sudo DEBIAN_FRONTEND=noninteractive apt-get -y install nullmailer >/dev/null && which sendmail
|
||||||
|
- name: Run go test
|
||||||
|
if: success()
|
||||||
|
run: |
|
||||||
|
go test -race -shuffle=on --coverprofile=coverage.coverprofile --covermode=atomic ./...
|
||||||
|
- name: Upload coverage to Codecov
|
||||||
|
if: success()
|
||||||
|
uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4.6.0
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.CODECOV_TOKEN }} # not required for public repos
|
||||||
|
lint:
|
||||||
|
name: golangci-lint (${{ matrix.go }})
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
concurrency:
|
||||||
|
group: ci-lint-${{ matrix.go }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
go: ['1.23']
|
||||||
|
steps:
|
||||||
|
- name: Harden Runner
|
||||||
|
uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
|
||||||
|
with:
|
||||||
|
egress-policy: audit
|
||||||
|
- name: Setup go
|
||||||
|
uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0
|
||||||
|
with:
|
||||||
|
go-version: ${{ matrix.go }}
|
||||||
|
check-latest: true
|
||||||
|
- name: Checkout Code
|
||||||
|
uses: actions/checkout@61b9e3751b92087fd0b06925ba6dd6314e06f089 # master
|
||||||
|
- name: golangci-lint
|
||||||
|
uses: golangci/golangci-lint-action@971e284b6050e8a5849b72094c50ab08da042db8 # v6.1.1
|
||||||
|
with:
|
||||||
|
version: latest
|
||||||
|
dependency-review:
|
||||||
|
name: Dependency review
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
concurrency:
|
||||||
|
group: ci-dependency-review
|
||||||
|
cancel-in-progress: true
|
||||||
|
steps:
|
||||||
|
- name: Harden Runner
|
||||||
|
uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
|
||||||
|
with:
|
||||||
|
egress-policy: audit
|
||||||
|
- name: Checkout Code
|
||||||
|
uses: actions/checkout@61b9e3751b92087fd0b06925ba6dd6314e06f089 # master
|
||||||
|
- name: 'Dependency Review'
|
||||||
|
uses: actions/dependency-review-action@a6993e2c61fd5dc440b409aa1d6904921c5e1894 # v4.3.5
|
||||||
|
govulncheck:
|
||||||
|
name: Go vulnerabilities check
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
concurrency:
|
||||||
|
group: ci-govulncheck
|
||||||
|
cancel-in-progress: true
|
||||||
|
steps:
|
||||||
|
- name: Harden Runner
|
||||||
|
uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
|
||||||
|
with:
|
||||||
|
egress-policy: audit
|
||||||
|
- name: Run govulncheck
|
||||||
|
uses: golang/govulncheck-action@b625fbe08f3bccbe446d94fbf87fcc875a4f50ee # v1.0.4
|
||||||
|
test:
|
||||||
|
name: Test (${{ matrix.os }} / ${{ matrix.go }})
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
concurrency:
|
||||||
|
group: ci-test-${{ matrix.os }}-${{ matrix.go }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||||
|
go: ['1.19', '1.20', '1.21', '1.22', '1.23']
|
||||||
|
steps:
|
||||||
|
- name: Harden Runner
|
||||||
|
uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
|
||||||
|
with:
|
||||||
|
egress-policy: audit
|
||||||
|
- name: Checkout Code
|
||||||
|
uses: actions/checkout@61b9e3751b92087fd0b06925ba6dd6314e06f089 # master
|
||||||
|
- name: Setup go
|
||||||
|
uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0
|
||||||
|
with:
|
||||||
|
go-version: ${{ matrix.go }}
|
||||||
|
- name: Run go test
|
||||||
|
run: |
|
||||||
|
go test -race -shuffle=on ./...
|
||||||
|
reuse:
|
||||||
|
name: REUSE Compliance Check
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
concurrency:
|
||||||
|
group: ci-reuse
|
||||||
|
cancel-in-progress: true
|
||||||
|
steps:
|
||||||
|
- name: Harden Runner
|
||||||
|
uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
|
||||||
|
with:
|
||||||
|
egress-policy: audit
|
||||||
|
- name: Checkout Code
|
||||||
|
uses: actions/checkout@61b9e3751b92087fd0b06925ba6dd6314e06f089 # master
|
||||||
|
- name: REUSE Compliance Check
|
||||||
|
uses: fsfe/reuse-action@3ae3c6bdf1257ab19397fab11fd3312144692083 # v4.0.0
|
||||||
|
sonarqube:
|
||||||
|
name: Test with SonarQube review (${{ matrix.os }} / ${{ matrix.go }})
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
concurrency:
|
||||||
|
group: ci-codecov-${{ matrix.go }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest]
|
||||||
|
go: ['1.23']
|
||||||
|
env:
|
||||||
|
PERFORM_ONLINE_TEST: ${{ vars.PERFORM_ONLINE_TEST }}
|
||||||
|
TEST_HOST: ${{ secrets.TEST_HOST }}
|
||||||
|
TEST_USER: ${{ secrets.TEST_USER }}
|
||||||
|
TEST_PASS: ${{ secrets.TEST_PASS }}
|
||||||
|
steps:
|
||||||
|
- name: Harden Runner
|
||||||
|
uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
|
||||||
|
with:
|
||||||
|
egress-policy: audit
|
||||||
|
- name: Checkout Code
|
||||||
|
uses: actions/checkout@61b9e3751b92087fd0b06925ba6dd6314e06f089 # master
|
||||||
|
- name: Setup go
|
||||||
|
uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0
|
||||||
|
with:
|
||||||
|
go-version: ${{ matrix.go }}
|
||||||
|
check-latest: true
|
||||||
|
- name: Run go test
|
||||||
|
run: |
|
||||||
|
go test -shuffle=on -race --coverprofile=./cov.out ./...
|
||||||
|
- name: SonarQube scan
|
||||||
|
uses: sonarsource/sonarqube-scan-action@884b79409bbd464b2a59edc326a4b77dc56b2195 # master
|
||||||
|
if: success()
|
||||||
|
env:
|
||||||
|
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||||
|
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
|
||||||
|
- name: SonarQube quality gate
|
||||||
|
uses: sonarsource/sonarqube-quality-gate-action@dc2f7b0dd95544cd550de3028f89193576e958b9 # master
|
||||||
|
timeout-minutes: 5
|
||||||
|
env:
|
||||||
|
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||||
|
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
|
67
.github/workflows/codecov.yml
vendored
67
.github/workflows/codecov.yml
vendored
|
@ -1,67 +0,0 @@
|
||||||
# SPDX-FileCopyrightText: 2022 Winni Neessen <winni@neessen.dev>
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: CC0-1.0
|
|
||||||
|
|
||||||
name: Codecov workflow
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
paths:
|
|
||||||
- '**.go'
|
|
||||||
- 'go.*'
|
|
||||||
- '.github/workflows/codecov.yml'
|
|
||||||
- 'codecov.yml'
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
paths:
|
|
||||||
- '**.go'
|
|
||||||
- 'go.*'
|
|
||||||
- '.github/workflows/codecov.yml'
|
|
||||||
- 'codecov.yml'
|
|
||||||
env:
|
|
||||||
TEST_HOST: ${{ secrets.TEST_HOST }}
|
|
||||||
TEST_FROM: ${{ secrets.TEST_USER }}
|
|
||||||
TEST_ALLOW_SEND: "1"
|
|
||||||
TEST_SMTPAUTH_USER: ${{ secrets.TEST_USER }}
|
|
||||||
TEST_SMTPAUTH_PASS: ${{ secrets.TEST_PASS }}
|
|
||||||
TEST_SMTPAUTH_TYPE: "LOGIN"
|
|
||||||
TEST_ONLINE_SCRAM: "1"
|
|
||||||
TEST_HOST_SCRAM: ${{ secrets.TEST_HOST_SCRAM }}
|
|
||||||
TEST_USER_SCRAM: ${{ secrets.TEST_USER_SCRAM }}
|
|
||||||
TEST_PASS_SCRAM: ${{ secrets.TEST_PASS_SCRAM }}
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
run:
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
||||||
go: ['1.23']
|
|
||||||
steps:
|
|
||||||
- name: Harden Runner
|
|
||||||
uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
|
|
||||||
with:
|
|
||||||
egress-policy: audit
|
|
||||||
|
|
||||||
- name: Checkout Code
|
|
||||||
uses: actions/checkout@61b9e3751b92087fd0b06925ba6dd6314e06f089 # master
|
|
||||||
- name: Setup go
|
|
||||||
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
|
|
||||||
with:
|
|
||||||
go-version: ${{ matrix.go }}
|
|
||||||
- name: Install sendmail
|
|
||||||
if: matrix.go == '1.23' && matrix.os == 'ubuntu-latest'
|
|
||||||
run: |
|
|
||||||
sudo apt-get -y install sendmail; which sendmail
|
|
||||||
- name: Run Tests
|
|
||||||
run: |
|
|
||||||
go test -race --coverprofile=coverage.coverprofile --covermode=atomic ./...
|
|
||||||
- name: Upload coverage to Codecov
|
|
||||||
if: success() && matrix.go == '1.23' && matrix.os == 'ubuntu-latest'
|
|
||||||
uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4.6.0
|
|
||||||
with:
|
|
||||||
token: ${{ secrets.CODECOV_TOKEN }} # not required for public repos
|
|
31
.github/workflows/dependency-review.yml
vendored
31
.github/workflows/dependency-review.yml
vendored
|
@ -1,31 +0,0 @@
|
||||||
# SPDX-FileCopyrightText: 2022-2023 The go-mail Authors
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: CC0-1.0
|
|
||||||
|
|
||||||
# Dependency Review Action
|
|
||||||
#
|
|
||||||
# This Action will scan dependency manifest files that change as part of a Pull Request,
|
|
||||||
# surfacing known-vulnerable versions of the packages declared or updated in the PR.
|
|
||||||
# Once installed, if the workflow run is marked as required,
|
|
||||||
# PRs introducing known-vulnerable packages will be blocked from merging.
|
|
||||||
#
|
|
||||||
# Source repository: https://github.com/actions/dependency-review-action
|
|
||||||
name: 'Dependency Review'
|
|
||||||
on: [pull_request]
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
dependency-review:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Harden Runner
|
|
||||||
uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
|
|
||||||
with:
|
|
||||||
egress-policy: audit
|
|
||||||
|
|
||||||
- name: 'Checkout Repository'
|
|
||||||
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
|
||||||
- name: 'Dependency Review'
|
|
||||||
uses: actions/dependency-review-action@a6993e2c61fd5dc440b409aa1d6904921c5e1894 # v4.3.5
|
|
54
.github/workflows/golangci-lint.yml
vendored
54
.github/workflows/golangci-lint.yml
vendored
|
@ -1,54 +0,0 @@
|
||||||
# SPDX-FileCopyrightText: 2022 Winni Neessen <winni@neessen.dev>
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: CC0-1.0
|
|
||||||
|
|
||||||
name: golangci-lint
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
tags:
|
|
||||||
- v*
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
pull_request:
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
# Optional: allow read access to pull request. Use with `only-new-issues` option.
|
|
||||||
# pull-requests: read
|
|
||||||
jobs:
|
|
||||||
golangci:
|
|
||||||
name: lint
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Harden Runner
|
|
||||||
uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
|
|
||||||
with:
|
|
||||||
egress-policy: audit
|
|
||||||
|
|
||||||
- uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
|
|
||||||
with:
|
|
||||||
go-version: '1.23'
|
|
||||||
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
|
||||||
- name: golangci-lint
|
|
||||||
uses: golangci/golangci-lint-action@971e284b6050e8a5849b72094c50ab08da042db8 # v6.1.1
|
|
||||||
with:
|
|
||||||
# Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version
|
|
||||||
version: latest
|
|
||||||
|
|
||||||
# Optional: working directory, useful for monorepos
|
|
||||||
# working-directory: somedir
|
|
||||||
|
|
||||||
# Optional: golangci-lint command line arguments.
|
|
||||||
# args: --issues-exit-code=0
|
|
||||||
|
|
||||||
# Optional: show only new issues if it's a pull request. The default value is `false`.
|
|
||||||
# only-new-issues: true
|
|
||||||
|
|
||||||
# Optional: if set to true then the all caching functionality will be complete disabled,
|
|
||||||
# takes precedence over all other caching options.
|
|
||||||
# skip-cache: true
|
|
||||||
|
|
||||||
# Optional: if set to true then the action don't cache or restore ~/go/pkg.
|
|
||||||
# skip-pkg-cache: true
|
|
||||||
|
|
||||||
# Optional: if set to true then the action don't cache or restore ~/.cache/go-build.
|
|
||||||
# skip-build-cache: true
|
|
21
.github/workflows/govulncheck.yml
vendored
21
.github/workflows/govulncheck.yml
vendored
|
@ -1,21 +0,0 @@
|
||||||
# SPDX-FileCopyrightText: 2022 Winni Neessen <winni@neessen.dev>
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: CC0-1.0
|
|
||||||
|
|
||||||
name: Govulncheck Security Scan
|
|
||||||
|
|
||||||
on: [push, pull_request]
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Harden Runner
|
|
||||||
uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
|
|
||||||
with:
|
|
||||||
egress-policy: audit
|
|
||||||
- name: Run govulncheck
|
|
||||||
uses: golang/govulncheck-action@b625fbe08f3bccbe446d94fbf87fcc875a4f50ee # v1.0.4
|
|
45
.github/workflows/offline-tests.yml
vendored
45
.github/workflows/offline-tests.yml
vendored
|
@ -1,45 +0,0 @@
|
||||||
# SPDX-FileCopyrightText: 2022 Winni Neessen <winni@neessen.dev>
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: CC0-1.0
|
|
||||||
|
|
||||||
name: Offline tests workflow
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
paths:
|
|
||||||
- '**.go'
|
|
||||||
- 'go.*'
|
|
||||||
- '.github/workflows/offline-tests.yml'
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
paths:
|
|
||||||
- '**.go'
|
|
||||||
- 'go.*'
|
|
||||||
- '.github/workflows/offline-tests.yml'
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
run:
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
||||||
go: ['1.19', '1.20', '1.21', '1.22', '1.23']
|
|
||||||
steps:
|
|
||||||
- name: Harden Runner
|
|
||||||
uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
|
|
||||||
with:
|
|
||||||
egress-policy: audit
|
|
||||||
|
|
||||||
- name: Checkout Code
|
|
||||||
uses: actions/checkout@61b9e3751b92087fd0b06925ba6dd6314e06f089 # master
|
|
||||||
- name: Setup go
|
|
||||||
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
|
|
||||||
with:
|
|
||||||
go-version: ${{ matrix.go }}
|
|
||||||
- name: Run Tests
|
|
||||||
run: |
|
|
||||||
go test -race -shuffle=on ./...
|
|
23
.github/workflows/reuse.yml
vendored
23
.github/workflows/reuse.yml
vendored
|
@ -1,23 +0,0 @@
|
||||||
# SPDX-FileCopyrightText: 2022 Winni Neessen <winni@neessen.dev>
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: CC0-1.0
|
|
||||||
|
|
||||||
name: REUSE Compliance Check
|
|
||||||
|
|
||||||
on: [push, pull_request]
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Harden Runner
|
|
||||||
uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
|
|
||||||
with:
|
|
||||||
egress-policy: audit
|
|
||||||
|
|
||||||
- uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
|
|
||||||
- name: REUSE Compliance Check
|
|
||||||
uses: fsfe/reuse-action@3ae3c6bdf1257ab19397fab11fd3312144692083 # v4.0.0
|
|
56
.github/workflows/sonarqube.yml
vendored
56
.github/workflows/sonarqube.yml
vendored
|
@ -1,56 +0,0 @@
|
||||||
# SPDX-FileCopyrightText: 2022 Winni Neessen <winni@neessen.dev>
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: CC0-1.0
|
|
||||||
|
|
||||||
name: SonarQube
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
paths:
|
|
||||||
- '**.go'
|
|
||||||
- 'go.*'
|
|
||||||
- '.github/workflows/sonarqube.yml'
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
paths:
|
|
||||||
- '**.go'
|
|
||||||
- 'go.*'
|
|
||||||
- '.github/workflows/sonarqube.yml'
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
name: Build
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Harden Runner
|
|
||||||
uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
|
|
||||||
with:
|
|
||||||
egress-policy: audit
|
|
||||||
|
|
||||||
- uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Setup Go
|
|
||||||
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2
|
|
||||||
with:
|
|
||||||
go-version: '1.23'
|
|
||||||
|
|
||||||
- name: Run unit Tests
|
|
||||||
run: |
|
|
||||||
go test -shuffle=on -race --coverprofile=./cov.out ./...
|
|
||||||
|
|
||||||
- uses: sonarsource/sonarqube-scan-action@884b79409bbd464b2a59edc326a4b77dc56b2195 # master
|
|
||||||
env:
|
|
||||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
|
||||||
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
|
|
||||||
|
|
||||||
- uses: sonarsource/sonarqube-quality-gate-action@dc2f7b0dd95544cd550de3028f89193576e958b9 # master
|
|
||||||
timeout-minutes: 5
|
|
||||||
env:
|
|
||||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
|
126
client_121_test.go
Normal file
126
client_121_test.go
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
// SPDX-FileCopyrightText: 2024 The go-mail Authors
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
//go:build go1.21
|
||||||
|
// +build go1.21
|
||||||
|
|
||||||
|
package mail
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/wneessen/go-mail/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNewClientNewVersionsOnly(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
option Option
|
||||||
|
expectFunc func(c *Client) error
|
||||||
|
shouldfail bool
|
||||||
|
expectErr *error
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"WithLogger log.JSONlog", WithLogger(log.NewJSON(os.Stderr, log.LevelDebug)),
|
||||||
|
func(c *Client) error {
|
||||||
|
if c.logger == nil {
|
||||||
|
return errors.New("failed to set logger. Want logger bug got got nil")
|
||||||
|
}
|
||||||
|
loggerType := reflect.TypeOf(c.logger).String()
|
||||||
|
if loggerType != "*log.JSONlog" {
|
||||||
|
return fmt.Errorf("failed to set logger. Want logger type: %s, got: %s",
|
||||||
|
"*log.JSONlog", loggerType)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
false, nil,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
client, err := NewClient(DefaultHost, tt.option)
|
||||||
|
if !tt.shouldfail && err != nil {
|
||||||
|
t.Fatalf("failed to create new client: %s", err)
|
||||||
|
}
|
||||||
|
if tt.shouldfail && err == nil {
|
||||||
|
t.Errorf("client creation was supposed to fail, but it didn't")
|
||||||
|
}
|
||||||
|
if tt.shouldfail && tt.expectErr != nil {
|
||||||
|
if !errors.Is(err, *tt.expectErr) {
|
||||||
|
t.Errorf("error for NewClient mismatch. Expected: %s, got: %s",
|
||||||
|
*tt.expectErr, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if tt.expectFunc != nil {
|
||||||
|
if err = tt.expectFunc(client); err != nil {
|
||||||
|
t.Errorf("NewClient with custom option failed: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestClient_DialWithContextNewVersionsOnly(t *testing.T) {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
PortAdder.Add(1)
|
||||||
|
serverPort := int(TestServerPortBase + PortAdder.Load())
|
||||||
|
featureSet := "250-AUTH PLAIN\r\n250-8BITMIME\r\n250-DSN\r\n250 SMTPUTF8"
|
||||||
|
go func() {
|
||||||
|
if err := simpleSMTPServer(ctx, t, &serverProps{FeatureSet: featureSet, ListenPort: serverPort}); err != nil {
|
||||||
|
t.Errorf("failed to start test server: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
time.Sleep(time.Millisecond * 30)
|
||||||
|
t.Run("connect with full debug logging and auth logging", func(t *testing.T) {
|
||||||
|
ctxDial, cancelDial := context.WithTimeout(ctx, time.Millisecond*500)
|
||||||
|
t.Cleanup(cancelDial)
|
||||||
|
|
||||||
|
logBuffer := bytes.NewBuffer(nil)
|
||||||
|
client, err := NewClient(DefaultHost, WithPort(serverPort), WithTLSPolicy(NoTLS),
|
||||||
|
WithDebugLog(), WithLogAuthData(), WithLogger(log.NewJSON(logBuffer, log.LevelDebug)),
|
||||||
|
WithSMTPAuth(SMTPAuthPlain), WithUsername("test"), WithPassword("password"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create new client: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = client.DialWithContext(ctxDial); err != nil {
|
||||||
|
var netErr net.Error
|
||||||
|
if errors.As(err, &netErr) && netErr.Timeout() {
|
||||||
|
t.Skip("failed to connect to the test server due to timeout")
|
||||||
|
}
|
||||||
|
t.Fatalf("failed to connect to the test server: %s", err)
|
||||||
|
}
|
||||||
|
t.Cleanup(func() {
|
||||||
|
if err = client.Close(); err != nil {
|
||||||
|
t.Errorf("failed to close the client: %s", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
logs := parseJSONLog(t, logBuffer)
|
||||||
|
if len(logs.Lines) == 0 {
|
||||||
|
t.Errorf("failed to enable debug logging, but no logs were found")
|
||||||
|
}
|
||||||
|
authFound := false
|
||||||
|
for _, logline := range logs.Lines {
|
||||||
|
if strings.EqualFold(logline.Message, "AUTH PLAIN AHRlc3QAcGFzc3dvcmQ=") &&
|
||||||
|
logline.Direction.From == "client" && logline.Direction.To == "server" {
|
||||||
|
authFound = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !authFound {
|
||||||
|
t.Errorf("logAuthData not working, no authentication info found in logs")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
203
client_test.go
203
client_test.go
|
@ -29,7 +29,7 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// DefaultHost is used as default hostname for the Client
|
// DefaultHost is used as default hostname for the Client
|
||||||
DefaultHost = "localhost"
|
DefaultHost = "127.0.0.1"
|
||||||
// TestRcpt is a trash mail address to send test mails to
|
// TestRcpt is a trash mail address to send test mails to
|
||||||
TestRcpt = "couttifaddebro-1473@yopmail.com"
|
TestRcpt = "couttifaddebro-1473@yopmail.com"
|
||||||
// TestServerProto is the protocol used for the simple SMTP test server
|
// TestServerProto is the protocol used for the simple SMTP test server
|
||||||
|
@ -268,21 +268,6 @@ func TestNewClient(t *testing.T) {
|
||||||
},
|
},
|
||||||
false, nil,
|
false, nil,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"WithLogger log.JSONlog", WithLogger(log.NewJSON(os.Stderr, log.LevelDebug)),
|
|
||||||
func(c *Client) error {
|
|
||||||
if c.logger == nil {
|
|
||||||
return errors.New("failed to set logger. Want logger bug got got nil")
|
|
||||||
}
|
|
||||||
loggerType := reflect.TypeOf(c.logger).String()
|
|
||||||
if loggerType != "*log.JSONlog" {
|
|
||||||
return fmt.Errorf("failed to set logger. Want logger type: %s, got: %s",
|
|
||||||
"*log.JSONlog", loggerType)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
false, nil,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"WithHELO", WithHELO(hostname),
|
"WithHELO", WithHELO(hostname),
|
||||||
func(c *Client) error {
|
func(c *Client) error {
|
||||||
|
@ -1181,6 +1166,10 @@ func TestClient_SetDebugLog(t *testing.T) {
|
||||||
client.SetDebugLog(true)
|
client.SetDebugLog(true)
|
||||||
|
|
||||||
if err = client.DialWithContext(ctxDial); err != nil {
|
if err = client.DialWithContext(ctxDial); err != nil {
|
||||||
|
var netErr net.Error
|
||||||
|
if errors.As(err, &netErr) && netErr.Timeout() {
|
||||||
|
t.Skip("failed to connect to the test server due to timeout")
|
||||||
|
}
|
||||||
t.Fatalf("failed to connect to test server: %s", err)
|
t.Fatalf("failed to connect to test server: %s", err)
|
||||||
}
|
}
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
|
@ -1210,6 +1199,10 @@ func TestClient_SetDebugLog(t *testing.T) {
|
||||||
client.SetDebugLog(false)
|
client.SetDebugLog(false)
|
||||||
|
|
||||||
if err = client.DialWithContext(ctxDial); err != nil {
|
if err = client.DialWithContext(ctxDial); err != nil {
|
||||||
|
var netErr net.Error
|
||||||
|
if errors.As(err, &netErr) && netErr.Timeout() {
|
||||||
|
t.Skip("failed to connect to the test server due to timeout")
|
||||||
|
}
|
||||||
t.Fatalf("failed to connect to test server: %s", err)
|
t.Fatalf("failed to connect to test server: %s", err)
|
||||||
}
|
}
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
|
@ -1235,6 +1228,10 @@ func TestClient_SetDebugLog(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = client.DialWithContext(ctxDial); err != nil {
|
if err = client.DialWithContext(ctxDial); err != nil {
|
||||||
|
var netErr net.Error
|
||||||
|
if errors.As(err, &netErr) && netErr.Timeout() {
|
||||||
|
t.Skip("failed to connect to the test server due to timeout")
|
||||||
|
}
|
||||||
t.Fatalf("failed to connect to test server: %s", err)
|
t.Fatalf("failed to connect to test server: %s", err)
|
||||||
}
|
}
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
|
@ -1559,6 +1556,10 @@ func TestClient_Close(t *testing.T) {
|
||||||
t.Fatalf("failed to create new client: %s", err)
|
t.Fatalf("failed to create new client: %s", err)
|
||||||
}
|
}
|
||||||
if err = client.DialWithContext(ctxDial); err != nil {
|
if err = client.DialWithContext(ctxDial); err != nil {
|
||||||
|
var netErr net.Error
|
||||||
|
if errors.As(err, &netErr) && netErr.Timeout() {
|
||||||
|
t.Skip("failed to connect to the test server due to timeout")
|
||||||
|
}
|
||||||
t.Fatalf("failed to connect to the test server: %s", err)
|
t.Fatalf("failed to connect to the test server: %s", err)
|
||||||
}
|
}
|
||||||
if !client.smtpClient.HasConnection() {
|
if !client.smtpClient.HasConnection() {
|
||||||
|
@ -1593,6 +1594,10 @@ func TestClient_Close(t *testing.T) {
|
||||||
t.Fatalf("failed to create new client: %s", err)
|
t.Fatalf("failed to create new client: %s", err)
|
||||||
}
|
}
|
||||||
if err = client.DialWithContext(ctxDial); err != nil {
|
if err = client.DialWithContext(ctxDial); err != nil {
|
||||||
|
var netErr net.Error
|
||||||
|
if errors.As(err, &netErr) && netErr.Timeout() {
|
||||||
|
t.Skip("failed to connect to the test server due to timeout")
|
||||||
|
}
|
||||||
t.Fatalf("failed to connect to the test server: %s", err)
|
t.Fatalf("failed to connect to the test server: %s", err)
|
||||||
}
|
}
|
||||||
if !client.smtpClient.HasConnection() {
|
if !client.smtpClient.HasConnection() {
|
||||||
|
@ -1631,6 +1636,10 @@ func TestClient_Close(t *testing.T) {
|
||||||
t.Fatalf("failed to create new client: %s", err)
|
t.Fatalf("failed to create new client: %s", err)
|
||||||
}
|
}
|
||||||
if err = client.DialWithContext(ctxDial); err != nil {
|
if err = client.DialWithContext(ctxDial); err != nil {
|
||||||
|
var netErr net.Error
|
||||||
|
if errors.As(err, &netErr) && netErr.Timeout() {
|
||||||
|
t.Skip("failed to connect to the test server due to timeout")
|
||||||
|
}
|
||||||
t.Fatalf("failed to connect to the test server: %s", err)
|
t.Fatalf("failed to connect to the test server: %s", err)
|
||||||
}
|
}
|
||||||
if !client.smtpClient.HasConnection() {
|
if !client.smtpClient.HasConnection() {
|
||||||
|
@ -1665,6 +1674,10 @@ func TestClient_DialWithContext(t *testing.T) {
|
||||||
t.Fatalf("failed to create new client: %s", err)
|
t.Fatalf("failed to create new client: %s", err)
|
||||||
}
|
}
|
||||||
if err = client.DialWithContext(ctxDial); err != nil {
|
if err = client.DialWithContext(ctxDial); err != nil {
|
||||||
|
var netErr net.Error
|
||||||
|
if errors.As(err, &netErr) && netErr.Timeout() {
|
||||||
|
t.Skip("failed to connect to the test server due to timeout")
|
||||||
|
}
|
||||||
t.Fatalf("failed to connect to the test server: %s", err)
|
t.Fatalf("failed to connect to the test server: %s", err)
|
||||||
}
|
}
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
|
@ -1688,6 +1701,10 @@ func TestClient_DialWithContext(t *testing.T) {
|
||||||
client.fallbackPort = serverPort
|
client.fallbackPort = serverPort
|
||||||
|
|
||||||
if err = client.DialWithContext(ctxDial); err != nil {
|
if err = client.DialWithContext(ctxDial); err != nil {
|
||||||
|
var netErr net.Error
|
||||||
|
if errors.As(err, &netErr) && netErr.Timeout() {
|
||||||
|
t.Skip("failed to connect to the test server due to timeout")
|
||||||
|
}
|
||||||
t.Fatalf("failed to connect to the test server: %s", err)
|
t.Fatalf("failed to connect to the test server: %s", err)
|
||||||
}
|
}
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
|
@ -1759,42 +1776,6 @@ func TestClient_DialWithContext(t *testing.T) {
|
||||||
t.Fatalf("client has connection")
|
t.Fatalf("client has connection")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
t.Run("connect with full debug logging and auth logging", func(t *testing.T) {
|
|
||||||
ctxDial, cancelDial := context.WithTimeout(ctx, time.Millisecond*500)
|
|
||||||
t.Cleanup(cancelDial)
|
|
||||||
|
|
||||||
logBuffer := bytes.NewBuffer(nil)
|
|
||||||
client, err := NewClient(DefaultHost, WithPort(serverPort), WithTLSPolicy(NoTLS),
|
|
||||||
WithDebugLog(), WithLogAuthData(), WithLogger(log.NewJSON(logBuffer, log.LevelDebug)),
|
|
||||||
WithSMTPAuth(SMTPAuthPlain), WithUsername("test"), WithPassword("password"))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("failed to create new client: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = client.DialWithContext(ctxDial); err != nil {
|
|
||||||
t.Fatalf("failed to connect to the test server: %s", err)
|
|
||||||
}
|
|
||||||
t.Cleanup(func() {
|
|
||||||
if err = client.Close(); err != nil {
|
|
||||||
t.Errorf("failed to close the client: %s", err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
logs := parseJSONLog(t, logBuffer)
|
|
||||||
if len(logs.Lines) == 0 {
|
|
||||||
t.Errorf("failed to enable debug logging, but no logs were found")
|
|
||||||
}
|
|
||||||
authFound := false
|
|
||||||
for _, logline := range logs.Lines {
|
|
||||||
if strings.EqualFold(logline.Message, "AUTH PLAIN AHRlc3QAcGFzc3dvcmQ=") &&
|
|
||||||
logline.Direction.From == "client" && logline.Direction.To == "server" {
|
|
||||||
authFound = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !authFound {
|
|
||||||
t.Errorf("logAuthData not working, no authentication info found in logs")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
t.Run("connect should fail on HELO", func(t *testing.T) {
|
t.Run("connect should fail on HELO", func(t *testing.T) {
|
||||||
ctxFail, cancelFail := context.WithCancel(ctx)
|
ctxFail, cancelFail := context.WithCancel(ctx)
|
||||||
defer cancelFail()
|
defer cancelFail()
|
||||||
|
@ -1887,6 +1868,10 @@ func TestClient_DialWithContext(t *testing.T) {
|
||||||
t.Fatalf("failed to create new client: %s", err)
|
t.Fatalf("failed to create new client: %s", err)
|
||||||
}
|
}
|
||||||
if err = client.DialWithContext(ctxDial); err != nil {
|
if err = client.DialWithContext(ctxDial); err != nil {
|
||||||
|
var netErr net.Error
|
||||||
|
if errors.As(err, &netErr) && netErr.Timeout() {
|
||||||
|
t.Skip("failed to connect to the test server due to timeout")
|
||||||
|
}
|
||||||
t.Fatalf("failed to connect to the test server: %s", err)
|
t.Fatalf("failed to connect to the test server: %s", err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -1917,6 +1902,10 @@ func TestClient_DialWithContext(t *testing.T) {
|
||||||
t.Fatalf("failed to create new client: %s", err)
|
t.Fatalf("failed to create new client: %s", err)
|
||||||
}
|
}
|
||||||
if err = client.DialWithContext(ctxDial); err != nil {
|
if err = client.DialWithContext(ctxDial); err != nil {
|
||||||
|
var netErr net.Error
|
||||||
|
if errors.As(err, &netErr) && netErr.Timeout() {
|
||||||
|
t.Skip("failed to connect to the test server due to timeout")
|
||||||
|
}
|
||||||
t.Fatalf("failed to connect to the test server: %s", err)
|
t.Fatalf("failed to connect to the test server: %s", err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -2009,6 +1998,10 @@ func TestClient_DialWithContext(t *testing.T) {
|
||||||
t.Fatalf("failed to create new client: %s", err)
|
t.Fatalf("failed to create new client: %s", err)
|
||||||
}
|
}
|
||||||
if err = client.DialWithContext(ctxDial); err != nil {
|
if err = client.DialWithContext(ctxDial); err != nil {
|
||||||
|
var netErr net.Error
|
||||||
|
if errors.As(err, &netErr) && netErr.Timeout() {
|
||||||
|
t.Skip("failed to connect to the test server due to timeout")
|
||||||
|
}
|
||||||
t.Fatalf("failed to connect to the test server: %s", err)
|
t.Fatalf("failed to connect to the test server: %s", err)
|
||||||
}
|
}
|
||||||
if err := client.Close(); err != nil {
|
if err := client.Close(); err != nil {
|
||||||
|
@ -2040,6 +2033,10 @@ func TestClient_Reset(t *testing.T) {
|
||||||
t.Fatalf("failed to create new client: %s", err)
|
t.Fatalf("failed to create new client: %s", err)
|
||||||
}
|
}
|
||||||
if err = client.DialWithContext(ctxDial); err != nil {
|
if err = client.DialWithContext(ctxDial); err != nil {
|
||||||
|
var netErr net.Error
|
||||||
|
if errors.As(err, &netErr) && netErr.Timeout() {
|
||||||
|
t.Skip("failed to connect to the test server due to timeout")
|
||||||
|
}
|
||||||
t.Fatalf("failed to connect to the test server: %s", err)
|
t.Fatalf("failed to connect to the test server: %s", err)
|
||||||
}
|
}
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
|
@ -2073,6 +2070,10 @@ func TestClient_Reset(t *testing.T) {
|
||||||
t.Fatalf("failed to create new client: %s", err)
|
t.Fatalf("failed to create new client: %s", err)
|
||||||
}
|
}
|
||||||
if err = client.DialWithContext(ctxDial); err != nil {
|
if err = client.DialWithContext(ctxDial); err != nil {
|
||||||
|
var netErr net.Error
|
||||||
|
if errors.As(err, &netErr) && netErr.Timeout() {
|
||||||
|
t.Skip("failed to connect to the test server due to timeout")
|
||||||
|
}
|
||||||
t.Fatalf("failed to connect to the test server: %s", err)
|
t.Fatalf("failed to connect to the test server: %s", err)
|
||||||
}
|
}
|
||||||
if err = client.Close(); err != nil {
|
if err = client.Close(); err != nil {
|
||||||
|
@ -2108,6 +2109,10 @@ func TestClient_Reset(t *testing.T) {
|
||||||
t.Fatalf("failed to create new client: %s", err)
|
t.Fatalf("failed to create new client: %s", err)
|
||||||
}
|
}
|
||||||
if err = client.DialWithContext(ctxDial); err != nil {
|
if err = client.DialWithContext(ctxDial); err != nil {
|
||||||
|
var netErr net.Error
|
||||||
|
if errors.As(err, &netErr) && netErr.Timeout() {
|
||||||
|
t.Skip("failed to connect to the test server due to timeout")
|
||||||
|
}
|
||||||
t.Fatalf("failed to connect to the test server: %s", err)
|
t.Fatalf("failed to connect to the test server: %s", err)
|
||||||
}
|
}
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
|
@ -2145,6 +2150,10 @@ func TestClient_DialAndSendWithContext(t *testing.T) {
|
||||||
t.Fatalf("failed to create new client: %s", err)
|
t.Fatalf("failed to create new client: %s", err)
|
||||||
}
|
}
|
||||||
if err = client.DialAndSend(message); err != nil {
|
if err = client.DialAndSend(message); err != nil {
|
||||||
|
var netErr net.Error
|
||||||
|
if errors.As(err, &netErr) && netErr.Timeout() {
|
||||||
|
t.Skip("failed to connect to the test server due to timeout")
|
||||||
|
}
|
||||||
t.Fatalf("failed to dial and send: %s", err)
|
t.Fatalf("failed to dial and send: %s", err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -2173,6 +2182,10 @@ func TestClient_DialAndSendWithContext(t *testing.T) {
|
||||||
t.Fatalf("failed to create new client: %s", err)
|
t.Fatalf("failed to create new client: %s", err)
|
||||||
}
|
}
|
||||||
if err = client.DialAndSendWithContext(ctxDial, message); err != nil {
|
if err = client.DialAndSendWithContext(ctxDial, message); err != nil {
|
||||||
|
var netErr net.Error
|
||||||
|
if errors.As(err, &netErr) && netErr.Timeout() {
|
||||||
|
t.Skip("failed to connect to the test server due to timeout")
|
||||||
|
}
|
||||||
t.Fatalf("failed to dial and send: %s", err)
|
t.Fatalf("failed to dial and send: %s", err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -2311,6 +2324,10 @@ func TestClient_auth(t *testing.T) {
|
||||||
t.Fatalf("failed to create new client: %s", err)
|
t.Fatalf("failed to create new client: %s", err)
|
||||||
}
|
}
|
||||||
if err = client.DialWithContext(ctxDial); err != nil {
|
if err = client.DialWithContext(ctxDial); err != nil {
|
||||||
|
var netErr net.Error
|
||||||
|
if errors.As(err, &netErr) && netErr.Timeout() {
|
||||||
|
t.Skip("failed to connect to the test server due to timeout")
|
||||||
|
}
|
||||||
t.Fatalf("failed to connect to test service: %s", err)
|
t.Fatalf("failed to connect to test service: %s", err)
|
||||||
}
|
}
|
||||||
if err := client.Close(); err != nil {
|
if err := client.Close(); err != nil {
|
||||||
|
@ -2498,6 +2515,10 @@ func TestClient_Send(t *testing.T) {
|
||||||
t.Fatalf("failed to create new client: %s", err)
|
t.Fatalf("failed to create new client: %s", err)
|
||||||
}
|
}
|
||||||
if err = client.DialWithContext(ctxDial); err != nil {
|
if err = client.DialWithContext(ctxDial); err != nil {
|
||||||
|
var netErr net.Error
|
||||||
|
if errors.As(err, &netErr) && netErr.Timeout() {
|
||||||
|
t.Skip("failed to connect to the test server due to timeout")
|
||||||
|
}
|
||||||
t.Fatalf("failed to connect to test server: %s", err)
|
t.Fatalf("failed to connect to test server: %s", err)
|
||||||
}
|
}
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
|
@ -2550,6 +2571,10 @@ func TestClient_Send(t *testing.T) {
|
||||||
t.Fatalf("failed to create new client: %s", err)
|
t.Fatalf("failed to create new client: %s", err)
|
||||||
}
|
}
|
||||||
if err = client.DialWithContext(ctxDial); err != nil {
|
if err = client.DialWithContext(ctxDial); err != nil {
|
||||||
|
var netErr net.Error
|
||||||
|
if errors.As(err, &netErr) && netErr.Timeout() {
|
||||||
|
t.Skip("failed to connect to the test server due to timeout")
|
||||||
|
}
|
||||||
t.Fatalf("failed to connect to test server: %s", err)
|
t.Fatalf("failed to connect to test server: %s", err)
|
||||||
}
|
}
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
|
@ -2607,6 +2632,10 @@ func TestClient_sendSingleMsg(t *testing.T) {
|
||||||
t.Fatalf("failed to create new client: %s", err)
|
t.Fatalf("failed to create new client: %s", err)
|
||||||
}
|
}
|
||||||
if err = client.DialWithContext(ctxDial); err != nil {
|
if err = client.DialWithContext(ctxDial); err != nil {
|
||||||
|
var netErr net.Error
|
||||||
|
if errors.As(err, &netErr) && netErr.Timeout() {
|
||||||
|
t.Skip("failed to connect to the test server due to timeout")
|
||||||
|
}
|
||||||
t.Fatalf("failed to connect to test server: %s", err)
|
t.Fatalf("failed to connect to test server: %s", err)
|
||||||
}
|
}
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
|
@ -2646,6 +2675,10 @@ func TestClient_sendSingleMsg(t *testing.T) {
|
||||||
t.Fatalf("failed to create new client: %s", err)
|
t.Fatalf("failed to create new client: %s", err)
|
||||||
}
|
}
|
||||||
if err = client.DialWithContext(ctxDial); err != nil {
|
if err = client.DialWithContext(ctxDial); err != nil {
|
||||||
|
var netErr net.Error
|
||||||
|
if errors.As(err, &netErr) && netErr.Timeout() {
|
||||||
|
t.Skip("failed to connect to the test server due to timeout")
|
||||||
|
}
|
||||||
t.Fatalf("failed to connect to test server: %s", err)
|
t.Fatalf("failed to connect to test server: %s", err)
|
||||||
}
|
}
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
|
@ -2687,6 +2720,10 @@ func TestClient_sendSingleMsg(t *testing.T) {
|
||||||
t.Fatalf("failed to create new client: %s", err)
|
t.Fatalf("failed to create new client: %s", err)
|
||||||
}
|
}
|
||||||
if err = client.DialWithContext(ctxDial); err != nil {
|
if err = client.DialWithContext(ctxDial); err != nil {
|
||||||
|
var netErr net.Error
|
||||||
|
if errors.As(err, &netErr) && netErr.Timeout() {
|
||||||
|
t.Skip("failed to connect to the test server due to timeout")
|
||||||
|
}
|
||||||
t.Fatalf("failed to connect to test server: %s", err)
|
t.Fatalf("failed to connect to test server: %s", err)
|
||||||
}
|
}
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
|
@ -2733,6 +2770,10 @@ func TestClient_sendSingleMsg(t *testing.T) {
|
||||||
t.Fatalf("failed to create new client: %s", err)
|
t.Fatalf("failed to create new client: %s", err)
|
||||||
}
|
}
|
||||||
if err = client.DialWithContext(ctxDial); err != nil {
|
if err = client.DialWithContext(ctxDial); err != nil {
|
||||||
|
var netErr net.Error
|
||||||
|
if errors.As(err, &netErr) && netErr.Timeout() {
|
||||||
|
t.Skip("failed to connect to the test server due to timeout")
|
||||||
|
}
|
||||||
t.Fatalf("failed to connect to test server: %s", err)
|
t.Fatalf("failed to connect to test server: %s", err)
|
||||||
}
|
}
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
|
@ -2779,6 +2820,10 @@ func TestClient_sendSingleMsg(t *testing.T) {
|
||||||
t.Fatalf("failed to create new client: %s", err)
|
t.Fatalf("failed to create new client: %s", err)
|
||||||
}
|
}
|
||||||
if err = client.DialWithContext(ctxDial); err != nil {
|
if err = client.DialWithContext(ctxDial); err != nil {
|
||||||
|
var netErr net.Error
|
||||||
|
if errors.As(err, &netErr) && netErr.Timeout() {
|
||||||
|
t.Skip("failed to connect to the test server due to timeout")
|
||||||
|
}
|
||||||
t.Fatalf("failed to connect to test server: %s", err)
|
t.Fatalf("failed to connect to test server: %s", err)
|
||||||
}
|
}
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
|
@ -2825,6 +2870,10 @@ func TestClient_sendSingleMsg(t *testing.T) {
|
||||||
t.Fatalf("failed to create new client: %s", err)
|
t.Fatalf("failed to create new client: %s", err)
|
||||||
}
|
}
|
||||||
if err = client.DialWithContext(ctxDial); err != nil {
|
if err = client.DialWithContext(ctxDial); err != nil {
|
||||||
|
var netErr net.Error
|
||||||
|
if errors.As(err, &netErr) && netErr.Timeout() {
|
||||||
|
t.Skip("failed to connect to the test server due to timeout")
|
||||||
|
}
|
||||||
t.Fatalf("failed to connect to test server: %s", err)
|
t.Fatalf("failed to connect to test server: %s", err)
|
||||||
}
|
}
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
|
@ -2864,6 +2913,10 @@ func TestClient_sendSingleMsg(t *testing.T) {
|
||||||
t.Fatalf("failed to create new client: %s", err)
|
t.Fatalf("failed to create new client: %s", err)
|
||||||
}
|
}
|
||||||
if err = client.DialWithContext(ctxDial); err != nil {
|
if err = client.DialWithContext(ctxDial); err != nil {
|
||||||
|
var netErr net.Error
|
||||||
|
if errors.As(err, &netErr) && netErr.Timeout() {
|
||||||
|
t.Skip("failed to connect to the test server due to timeout")
|
||||||
|
}
|
||||||
t.Fatalf("failed to connect to test server: %s", err)
|
t.Fatalf("failed to connect to test server: %s", err)
|
||||||
}
|
}
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
|
@ -2911,6 +2964,10 @@ func TestClient_sendSingleMsg(t *testing.T) {
|
||||||
t.Fatalf("failed to create new client: %s", err)
|
t.Fatalf("failed to create new client: %s", err)
|
||||||
}
|
}
|
||||||
if err = client.DialWithContext(ctxDial); err != nil {
|
if err = client.DialWithContext(ctxDial); err != nil {
|
||||||
|
var netErr net.Error
|
||||||
|
if errors.As(err, &netErr) && netErr.Timeout() {
|
||||||
|
t.Skip("failed to connect to the test server due to timeout")
|
||||||
|
}
|
||||||
t.Fatalf("failed to connect to test server: %s", err)
|
t.Fatalf("failed to connect to test server: %s", err)
|
||||||
}
|
}
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
|
@ -2958,6 +3015,10 @@ func TestClient_sendSingleMsg(t *testing.T) {
|
||||||
t.Fatalf("failed to create new client: %s", err)
|
t.Fatalf("failed to create new client: %s", err)
|
||||||
}
|
}
|
||||||
if err = client.DialWithContext(ctxDial); err != nil {
|
if err = client.DialWithContext(ctxDial); err != nil {
|
||||||
|
var netErr net.Error
|
||||||
|
if errors.As(err, &netErr) && netErr.Timeout() {
|
||||||
|
t.Skip("failed to connect to the test server due to timeout")
|
||||||
|
}
|
||||||
t.Fatalf("failed to connect to test server: %s", err)
|
t.Fatalf("failed to connect to test server: %s", err)
|
||||||
}
|
}
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
|
@ -3004,6 +3065,10 @@ func TestClient_sendSingleMsg(t *testing.T) {
|
||||||
t.Fatalf("failed to create new client: %s", err)
|
t.Fatalf("failed to create new client: %s", err)
|
||||||
}
|
}
|
||||||
if err = client.DialWithContext(ctxDial); err != nil {
|
if err = client.DialWithContext(ctxDial); err != nil {
|
||||||
|
var netErr net.Error
|
||||||
|
if errors.As(err, &netErr) && netErr.Timeout() {
|
||||||
|
t.Skip("failed to connect to the test server due to timeout")
|
||||||
|
}
|
||||||
t.Fatalf("failed to connect to test server: %s", err)
|
t.Fatalf("failed to connect to test server: %s", err)
|
||||||
}
|
}
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
|
@ -3050,6 +3115,10 @@ func TestClient_sendSingleMsg(t *testing.T) {
|
||||||
t.Fatalf("failed to create new client: %s", err)
|
t.Fatalf("failed to create new client: %s", err)
|
||||||
}
|
}
|
||||||
if err = client.DialWithContext(ctxDial); err != nil {
|
if err = client.DialWithContext(ctxDial); err != nil {
|
||||||
|
var netErr net.Error
|
||||||
|
if errors.As(err, &netErr) && netErr.Timeout() {
|
||||||
|
t.Skip("failed to connect to the test server due to timeout")
|
||||||
|
}
|
||||||
t.Fatalf("failed to connect to test server: %s", err)
|
t.Fatalf("failed to connect to test server: %s", err)
|
||||||
}
|
}
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
|
@ -3096,6 +3165,10 @@ func TestClient_checkConn(t *testing.T) {
|
||||||
t.Fatalf("failed to create new client: %s", err)
|
t.Fatalf("failed to create new client: %s", err)
|
||||||
}
|
}
|
||||||
if err = client.DialWithContext(ctxDial); err != nil {
|
if err = client.DialWithContext(ctxDial); err != nil {
|
||||||
|
var netErr net.Error
|
||||||
|
if errors.As(err, &netErr) && netErr.Timeout() {
|
||||||
|
t.Skip("failed to connect to the test server due to timeout")
|
||||||
|
}
|
||||||
t.Fatalf("failed to connect to test server: %s", err)
|
t.Fatalf("failed to connect to test server: %s", err)
|
||||||
}
|
}
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
|
@ -3133,6 +3206,10 @@ func TestClient_checkConn(t *testing.T) {
|
||||||
t.Fatalf("failed to create new client: %s", err)
|
t.Fatalf("failed to create new client: %s", err)
|
||||||
}
|
}
|
||||||
if err = client.DialWithContext(ctxDial); err != nil {
|
if err = client.DialWithContext(ctxDial); err != nil {
|
||||||
|
var netErr net.Error
|
||||||
|
if errors.As(err, &netErr) && netErr.Timeout() {
|
||||||
|
t.Skip("failed to connect to the test server due to timeout")
|
||||||
|
}
|
||||||
t.Fatalf("failed to connect to test server: %s", err)
|
t.Fatalf("failed to connect to test server: %s", err)
|
||||||
}
|
}
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
|
@ -3199,7 +3276,11 @@ func TestClient_onlinetests(t *testing.T) {
|
||||||
t.Cleanup(cancel)
|
t.Cleanup(cancel)
|
||||||
|
|
||||||
if err = client.DialWithContext(ctx); err != nil {
|
if err = client.DialWithContext(ctx); err != nil {
|
||||||
t.Errorf("failed to dial to test server: %s", err)
|
var netErr net.Error
|
||||||
|
if errors.As(err, &netErr) && netErr.Timeout() {
|
||||||
|
t.Skip("failed to connect to the test server due to timeout")
|
||||||
|
}
|
||||||
|
t.Fatalf("failed to dial to test server: %s", err)
|
||||||
}
|
}
|
||||||
if err = client.smtpClient.Noop(); err != nil {
|
if err = client.smtpClient.Noop(); err != nil {
|
||||||
t.Errorf("failed to send noop: %s", err)
|
t.Errorf("failed to send noop: %s", err)
|
||||||
|
@ -3241,7 +3322,11 @@ func TestClient_onlinetests(t *testing.T) {
|
||||||
t.Cleanup(cancel)
|
t.Cleanup(cancel)
|
||||||
|
|
||||||
if err = client.DialWithContext(ctx); err != nil {
|
if err = client.DialWithContext(ctx); err != nil {
|
||||||
t.Errorf("failed to dial to test server: %s", err)
|
var netErr net.Error
|
||||||
|
if errors.As(err, &netErr) && netErr.Timeout() {
|
||||||
|
t.Skip("failed to connect to the test server due to timeout")
|
||||||
|
}
|
||||||
|
t.Fatalf("failed to dial to test server: %s", err)
|
||||||
}
|
}
|
||||||
if err = client.smtpClient.Noop(); err != nil {
|
if err = client.smtpClient.Noop(); err != nil {
|
||||||
t.Errorf("failed to send noop: %s", err)
|
t.Errorf("failed to send noop: %s", err)
|
||||||
|
@ -3283,7 +3368,11 @@ func TestClient_onlinetests(t *testing.T) {
|
||||||
t.Cleanup(cancel)
|
t.Cleanup(cancel)
|
||||||
|
|
||||||
if err = client.DialWithContext(ctx); err != nil {
|
if err = client.DialWithContext(ctx); err != nil {
|
||||||
t.Errorf("failed to dial to test server: %s", err)
|
var netErr net.Error
|
||||||
|
if errors.As(err, &netErr) && netErr.Timeout() {
|
||||||
|
t.Skip("failed to connect to the test server due to timeout")
|
||||||
|
}
|
||||||
|
t.Fatalf("failed to dial to test server: %s", err)
|
||||||
}
|
}
|
||||||
if err = client.smtpClient.Noop(); err != nil {
|
if err = client.smtpClient.Noop(); err != nil {
|
||||||
t.Errorf("failed to send noop: %s", err)
|
t.Errorf("failed to send noop: %s", err)
|
||||||
|
@ -3325,6 +3414,10 @@ func TestClient_XOAuth2OnFaker(t *testing.T) {
|
||||||
t.Fatalf("unable to create new client: %v", err)
|
t.Fatalf("unable to create new client: %v", err)
|
||||||
}
|
}
|
||||||
if err = c.DialWithContext(context.Background()); err != nil {
|
if err = c.DialWithContext(context.Background()); err != nil {
|
||||||
|
var netErr net.Error
|
||||||
|
if errors.As(err, &netErr) && netErr.Timeout() {
|
||||||
|
t.Skip("failed to connect to the test server due to timeout")
|
||||||
|
}
|
||||||
t.Fatalf("unexpected dial error: %v", err)
|
t.Fatalf("unexpected dial error: %v", err)
|
||||||
}
|
}
|
||||||
if err = c.Close(); err != nil {
|
if err = c.Close(); err != nil {
|
||||||
|
|
|
@ -16,8 +16,8 @@ import (
|
||||||
|
|
||||||
// TestMsg_WriteToSendmailWithContext tests the WriteToSendmailWithContext() method of the Msg
|
// TestMsg_WriteToSendmailWithContext tests the WriteToSendmailWithContext() method of the Msg
|
||||||
func TestMsg_WriteToSendmailWithContext(t *testing.T) {
|
func TestMsg_WriteToSendmailWithContext(t *testing.T) {
|
||||||
if os.Getenv("TEST_SKIP_SENDMAIL") != "" {
|
if os.Getenv("TEST_SENDMAIL") != "true" {
|
||||||
t.Skipf("TEST_SKIP_SENDMAIL variable is set. Skipping sendmail test")
|
t.Skipf("TEST_SENDMAIL variable is not set. Skipping sendmail test")
|
||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
@ -45,8 +45,8 @@ func TestMsg_WriteToSendmailWithContext(t *testing.T) {
|
||||||
|
|
||||||
// TestMsg_WriteToSendmail will test the output to the local sendmail command
|
// TestMsg_WriteToSendmail will test the output to the local sendmail command
|
||||||
func TestMsg_WriteToSendmail(t *testing.T) {
|
func TestMsg_WriteToSendmail(t *testing.T) {
|
||||||
if os.Getenv("TEST_SKIP_SENDMAIL") != "" {
|
if os.Getenv("TEST_SENDMAIL") != "true" {
|
||||||
t.Skipf("TEST_SKIP_SENDMAIL variable is set. Skipping sendmail test")
|
t.Skipf("TEST_SENDMAIL variable is not set. Skipping sendmail test")
|
||||||
}
|
}
|
||||||
_, err := os.Stat(SendmailPath)
|
_, err := os.Stat(SendmailPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -113,8 +113,6 @@ var (
|
||||||
{`hi\ there@domain.tld`, false}, // Spaces must be quoted
|
{`hi\ there@domain.tld`, false}, // Spaces must be quoted
|
||||||
{"hello@tld", true}, // TLD is enough
|
{"hello@tld", true}, // TLD is enough
|
||||||
{`你好@域名.顶级域名`, true}, // We speak RFC6532
|
{`你好@域名.顶级域名`, true}, // We speak RFC6532
|
||||||
{`cow@[dead::beef]`, true}, // IPv6 is fine
|
|
||||||
{"1@[1.101.236.21]", true}, // IPv4 is fine
|
|
||||||
{"1@23456789", true}, // Hypothetically valid, if somebody registers that TLD
|
{"1@23456789", true}, // Hypothetically valid, if somebody registers that TLD
|
||||||
{"1@[23456789]", false}, // While 23456789 is decimal for 1.101.236.21 it is not RFC5322 compliant
|
{"1@[23456789]", false}, // While 23456789 is decimal for 1.101.236.21 it is not RFC5322 compliant
|
||||||
}
|
}
|
||||||
|
@ -1140,7 +1138,8 @@ func TestMsg_ToFromString(t *testing.T) {
|
||||||
|
|
||||||
// checkAddrHeader validates a single email address in the AddrHeader of a message.
|
// checkAddrHeader validates a single email address in the AddrHeader of a message.
|
||||||
func checkAddrHeader(t *testing.T, message *Msg, header AddrHeader, fn string, field, wantFields int,
|
func checkAddrHeader(t *testing.T, message *Msg, header AddrHeader, fn string, field, wantFields int,
|
||||||
wantMail, wantName string) {
|
wantMail, wantName string,
|
||||||
|
) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
addresses, ok := message.addrHeader[header]
|
addresses, ok := message.addrHeader[header]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
Loading…
Reference in a new issue