mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-30 01:27:31 +08:00
feat(email): integrate email service using AWS SES (#1158)
This commit is contained in:
92
Cargo.lock
generated
92
Cargo.lock
generated
@ -598,9 +598,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aws-credential-types"
|
name = "aws-credential-types"
|
||||||
version = "0.55.1"
|
version = "0.55.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f4232d3729eefc287adc0d5a8adc97b7d94eefffe6bbe94312cc86c7ab6b06ce"
|
checksum = "4cb57ac6088805821f78d282c0ba8aec809f11cbee10dda19a97b03ab040ccc2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aws-smithy-async",
|
"aws-smithy-async",
|
||||||
"aws-smithy-types",
|
"aws-smithy-types",
|
||||||
@ -612,9 +612,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aws-endpoint"
|
name = "aws-endpoint"
|
||||||
version = "0.55.1"
|
version = "0.55.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "87f04ab03b3f1cca91f7cccaa213056d732accb14e2e65debfacc1d28627d162"
|
checksum = "9c5f6f84a4f46f95a9bb71d9300b73cd67eb868bc43ae84f66ad34752299f4ac"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aws-smithy-http",
|
"aws-smithy-http",
|
||||||
"aws-smithy-types",
|
"aws-smithy-types",
|
||||||
@ -626,9 +626,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aws-http"
|
name = "aws-http"
|
||||||
version = "0.55.1"
|
version = "0.55.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e5ad8c53f7560baaf635b6aa811f3213d39b50555d100f83e43801652d4e318e"
|
checksum = "a754683c322f7dc5167484266489fdebdcd04d26e53c162cad1f3f949f2c5671"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aws-credential-types",
|
"aws-credential-types",
|
||||||
"aws-smithy-http",
|
"aws-smithy-http",
|
||||||
@ -701,6 +701,31 @@ dependencies = [
|
|||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aws-sdk-sesv2"
|
||||||
|
version = "0.27.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "28ec96086c4bda28c512b10c5c951d031651be454a512e511cf5fe91b21b9cc9"
|
||||||
|
dependencies = [
|
||||||
|
"aws-credential-types",
|
||||||
|
"aws-endpoint",
|
||||||
|
"aws-http",
|
||||||
|
"aws-sig-auth",
|
||||||
|
"aws-smithy-async",
|
||||||
|
"aws-smithy-client",
|
||||||
|
"aws-smithy-http",
|
||||||
|
"aws-smithy-http-tower",
|
||||||
|
"aws-smithy-json",
|
||||||
|
"aws-smithy-types",
|
||||||
|
"aws-types",
|
||||||
|
"bytes",
|
||||||
|
"http",
|
||||||
|
"regex",
|
||||||
|
"tokio-stream",
|
||||||
|
"tower",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aws-sdk-sso"
|
name = "aws-sdk-sso"
|
||||||
version = "0.26.0"
|
version = "0.26.0"
|
||||||
@ -754,9 +779,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aws-sig-auth"
|
name = "aws-sig-auth"
|
||||||
version = "0.55.1"
|
version = "0.55.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "24d77d879ab210e958ba65a6d3842969a596738c024989cd3e490cf9f9b560ec"
|
checksum = "84dc92a63ede3c2cbe43529cb87ffa58763520c96c6a46ca1ced80417afba845"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aws-credential-types",
|
"aws-credential-types",
|
||||||
"aws-sigv4",
|
"aws-sigv4",
|
||||||
@ -769,9 +794,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aws-sigv4"
|
name = "aws-sigv4"
|
||||||
version = "0.55.1"
|
version = "0.55.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4ab4eebc8ec484fb9eab04b15a5d1e71f3dc13bee8fdd2d9ed78bcd6ecbd7192"
|
checksum = "392fefab9d6fcbd76d518eb3b1c040b84728ab50f58df0c3c53ada4bea9d327e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aws-smithy-eventstream",
|
"aws-smithy-eventstream",
|
||||||
"aws-smithy-http",
|
"aws-smithy-http",
|
||||||
@ -790,9 +815,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aws-smithy-async"
|
name = "aws-smithy-async"
|
||||||
version = "0.55.1"
|
version = "0.55.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "88573bcfbe1dcfd54d4912846df028b42d6255cbf9ce07be216b1bbfd11fc4b9"
|
checksum = "ae23b9fe7a07d0919000116c4c5c0578303fbce6fc8d32efca1f7759d4c20faf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
@ -823,9 +848,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aws-smithy-client"
|
name = "aws-smithy-client"
|
||||||
version = "0.55.1"
|
version = "0.55.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b2f52352bae50d3337d5d6151b695d31a8c10ebea113eca5bead531f8301b067"
|
checksum = "5230d25d244a51339273b8870f0f77874cd4449fb4f8f629b21188ae10cfc0ba"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aws-smithy-async",
|
"aws-smithy-async",
|
||||||
"aws-smithy-http",
|
"aws-smithy-http",
|
||||||
@ -847,9 +872,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aws-smithy-eventstream"
|
name = "aws-smithy-eventstream"
|
||||||
version = "0.55.1"
|
version = "0.55.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "168f08f8439c8b317b578a695e514c5cd7b869e73849a2d6b71ced4de6ce193d"
|
checksum = "22d2a2bcc16e5c4d949ffd2b851da852b9bbed4bb364ed4ae371b42137ca06d9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aws-smithy-types",
|
"aws-smithy-types",
|
||||||
"bytes",
|
"bytes",
|
||||||
@ -858,9 +883,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aws-smithy-http"
|
name = "aws-smithy-http"
|
||||||
version = "0.55.1"
|
version = "0.55.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "03bcc02d7ed9649d855c8ce4a735e9848d7b8f7568aad0504c158e3baa955df8"
|
checksum = "b60e2133beb9fe6ffe0b70deca57aaeff0a35ad24a9c6fab2fd3b4f45b99fdb5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aws-smithy-eventstream",
|
"aws-smithy-eventstream",
|
||||||
"aws-smithy-types",
|
"aws-smithy-types",
|
||||||
@ -881,9 +906,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aws-smithy-http-tower"
|
name = "aws-smithy-http-tower"
|
||||||
version = "0.55.1"
|
version = "0.55.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "da88b3a860f65505996c29192d800f1aeb9480440f56d63aad33a3c12045017a"
|
checksum = "3a4d94f556c86a0dd916a5d7c39747157ea8cb909ca469703e20fee33e448b67"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aws-smithy-http",
|
"aws-smithy-http",
|
||||||
"aws-smithy-types",
|
"aws-smithy-types",
|
||||||
@ -897,9 +922,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aws-smithy-json"
|
name = "aws-smithy-json"
|
||||||
version = "0.55.1"
|
version = "0.55.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9b0c1e87d75cac889dca2a7f5ba280da2cde8122448e7fec1d614194dfa00c70"
|
checksum = "5ce3d6e6ebb00b2cce379f079ad5ec508f9bcc3a9510d9b9c1840ed1d6f8af39"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aws-smithy-types",
|
"aws-smithy-types",
|
||||||
]
|
]
|
||||||
@ -916,9 +941,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aws-smithy-types"
|
name = "aws-smithy-types"
|
||||||
version = "0.55.1"
|
version = "0.55.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cd0afc731fd1417d791f9145a1e0c30e23ae0beaab9b4814017708ead2fc20f1"
|
checksum = "58db46fc1f4f26be01ebdb821751b4e2482cd43aa2b64a0348fb89762defaffa"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64-simd",
|
"base64-simd",
|
||||||
"itoa",
|
"itoa",
|
||||||
@ -938,9 +963,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aws-types"
|
name = "aws-types"
|
||||||
version = "0.55.1"
|
version = "0.55.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b9b082e329d9a304d39e193ad5c7ab363a0d6507aca6965e0673a746686fb0cc"
|
checksum = "de0869598bfe46ec44ffe17e063ed33336e59df90356ca8ff0e8da6f7c1d994b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aws-credential-types",
|
"aws-credential-types",
|
||||||
"aws-smithy-async",
|
"aws-smithy-async",
|
||||||
@ -1795,11 +1820,16 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
|
|||||||
name = "external_services"
|
name = "external_services"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"async-trait",
|
||||||
"aws-config",
|
"aws-config",
|
||||||
"aws-sdk-kms",
|
"aws-sdk-kms",
|
||||||
|
"aws-sdk-sesv2",
|
||||||
|
"aws-smithy-client",
|
||||||
"base64 0.21.0",
|
"base64 0.21.0",
|
||||||
"common_utils",
|
"common_utils",
|
||||||
|
"dyn-clone",
|
||||||
"error-stack",
|
"error-stack",
|
||||||
|
"masking",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"router_env",
|
"router_env",
|
||||||
"serde",
|
"serde",
|
||||||
@ -2970,7 +3000,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "opentelemetry"
|
name = "opentelemetry"
|
||||||
version = "0.18.0"
|
version = "0.18.0"
|
||||||
source = "git+https://github.com/open-telemetry/opentelemetry-rust/?rev=44b90202fd744598db8b0ace5b8f0bad7ec45658#44b90202fd744598db8b0ace5b8f0bad7ec45658"
|
source = "git+https://github.com/open-telemetry/opentelemetry-rust?rev=44b90202fd744598db8b0ace5b8f0bad7ec45658#44b90202fd744598db8b0ace5b8f0bad7ec45658"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"opentelemetry_api",
|
"opentelemetry_api",
|
||||||
"opentelemetry_sdk",
|
"opentelemetry_sdk",
|
||||||
@ -2979,7 +3009,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "opentelemetry-otlp"
|
name = "opentelemetry-otlp"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
source = "git+https://github.com/open-telemetry/opentelemetry-rust/?rev=44b90202fd744598db8b0ace5b8f0bad7ec45658#44b90202fd744598db8b0ace5b8f0bad7ec45658"
|
source = "git+https://github.com/open-telemetry/opentelemetry-rust?rev=44b90202fd744598db8b0ace5b8f0bad7ec45658#44b90202fd744598db8b0ace5b8f0bad7ec45658"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"futures",
|
"futures",
|
||||||
@ -2996,7 +3026,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "opentelemetry-proto"
|
name = "opentelemetry-proto"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/open-telemetry/opentelemetry-rust/?rev=44b90202fd744598db8b0ace5b8f0bad7ec45658#44b90202fd744598db8b0ace5b8f0bad7ec45658"
|
source = "git+https://github.com/open-telemetry/opentelemetry-rust?rev=44b90202fd744598db8b0ace5b8f0bad7ec45658#44b90202fd744598db8b0ace5b8f0bad7ec45658"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures",
|
"futures",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
@ -3008,7 +3038,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "opentelemetry_api"
|
name = "opentelemetry_api"
|
||||||
version = "0.18.0"
|
version = "0.18.0"
|
||||||
source = "git+https://github.com/open-telemetry/opentelemetry-rust/?rev=44b90202fd744598db8b0ace5b8f0bad7ec45658#44b90202fd744598db8b0ace5b8f0bad7ec45658"
|
source = "git+https://github.com/open-telemetry/opentelemetry-rust?rev=44b90202fd744598db8b0ace5b8f0bad7ec45658#44b90202fd744598db8b0ace5b8f0bad7ec45658"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fnv",
|
"fnv",
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
@ -3023,7 +3053,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "opentelemetry_sdk"
|
name = "opentelemetry_sdk"
|
||||||
version = "0.18.0"
|
version = "0.18.0"
|
||||||
source = "git+https://github.com/open-telemetry/opentelemetry-rust/?rev=44b90202fd744598db8b0ace5b8f0bad7ec45658#44b90202fd744598db8b0ace5b8f0bad7ec45658"
|
source = "git+https://github.com/open-telemetry/opentelemetry-rust?rev=44b90202fd744598db8b0ace5b8f0bad7ec45658#44b90202fd744598db8b0ace5b8f0bad7ec45658"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"crossbeam-channel",
|
"crossbeam-channel",
|
||||||
|
|||||||
@ -242,6 +242,12 @@ paypal = { currency = "USD,INR", country = "US" }
|
|||||||
key_id = "" # The AWS key ID used by the KMS SDK for decrypting data.
|
key_id = "" # The AWS key ID used by the KMS SDK for decrypting data.
|
||||||
region = "" # The AWS region used by the KMS SDK for decrypting data.
|
region = "" # The AWS region used by the KMS SDK for decrypting data.
|
||||||
|
|
||||||
|
# EmailClient configuration. Only applicable when the `email` feature flag is enabled.
|
||||||
|
[email]
|
||||||
|
from_email = "notify@example.com" # Sender email
|
||||||
|
aws_region = "" # AWS region used by AWS SES
|
||||||
|
base_url = "" # Base url used when adding links that should redirect to self
|
||||||
|
|
||||||
[dummy_connector]
|
[dummy_connector]
|
||||||
payment_ttl = 172800 # Time to live for dummy connector payment in redis
|
payment_ttl = 172800 # Time to live for dummy connector payment in redis
|
||||||
payment_duration = 1000 # Fake delay duration for dummy connector payment
|
payment_duration = 1000 # Fake delay duration for dummy connector payment
|
||||||
|
|||||||
@ -149,6 +149,11 @@ stream = "SCHEDULER_STREAM"
|
|||||||
disabled = false
|
disabled = false
|
||||||
consumer_group = "SCHEDULER_GROUP"
|
consumer_group = "SCHEDULER_GROUP"
|
||||||
|
|
||||||
|
[email]
|
||||||
|
from_email = "notify@example.com"
|
||||||
|
aws_region = ""
|
||||||
|
base_url = ""
|
||||||
|
|
||||||
[bank_config.eps]
|
[bank_config.eps]
|
||||||
stripe = { banks = "arzte_und_apotheker_bank,austrian_anadi_bank_ag,bank_austria,bankhaus_carl_spangler,bankhaus_schelhammer_und_schattera_ag,bawag_psk_ag,bks_bank_ag,brull_kallmus_bank_ag,btv_vier_lander_bank,capital_bank_grawe_gruppe_ag,dolomitenbank,easybank_ag,erste_bank_und_sparkassen,hypo_alpeadriabank_international_ag,hypo_noe_lb_fur_niederosterreich_u_wien,hypo_oberosterreich_salzburg_steiermark,hypo_tirol_bank_ag,hypo_vorarlberg_bank_ag,hypo_bank_burgenland_aktiengesellschaft,marchfelder_bank,oberbank_ag,raiffeisen_bankengruppe_osterreich,schoellerbank_ag,sparda_bank_wien,volksbank_gruppe,volkskreditbank_ag,vr_bank_braunau" }
|
stripe = { banks = "arzte_und_apotheker_bank,austrian_anadi_bank_ag,bank_austria,bankhaus_carl_spangler,bankhaus_schelhammer_und_schattera_ag,bawag_psk_ag,bks_bank_ag,brull_kallmus_bank_ag,btv_vier_lander_bank,capital_bank_grawe_gruppe_ag,dolomitenbank,easybank_ag,erste_bank_und_sparkassen,hypo_alpeadriabank_international_ag,hypo_noe_lb_fur_niederosterreich_u_wien,hypo_oberosterreich_salzburg_steiermark,hypo_tirol_bank_ag,hypo_vorarlberg_bank_ag,hypo_bank_burgenland_aktiengesellschaft,marchfelder_bank,oberbank_ag,raiffeisen_bankengruppe_osterreich,schoellerbank_ag,sparda_bank_wien,volksbank_gruppe,volkskreditbank_ag,vr_bank_braunau" }
|
||||||
adyen = { banks = "bank_austria,bawag_psk_ag,dolomitenbank,easybank_ag,erste_bank_und_sparkassen,hypo_tirol_bank_ag,posojilnica_bank_e_gen,raiffeisen_bankengruppe_osterreich,schoellerbank_ag,sparda_bank_wien,volksbank_gruppe,volkskreditbank_ag" }
|
adyen = { banks = "bank_austria,bawag_psk_ag,dolomitenbank,easybank_ag,erste_bank_und_sparkassen,hypo_tirol_bank_ag,posojilnica_bank_e_gen,raiffeisen_bankengruppe_osterreich,schoellerbank_ag,sparda_bank_wien,volksbank_gruppe,volkskreditbank_ag" }
|
||||||
|
|||||||
@ -9,6 +9,7 @@ license = "Apache-2.0"
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
kms = ["dep:aws-config", "dep:aws-sdk-kms"]
|
kms = ["dep:aws-config", "dep:aws-sdk-kms"]
|
||||||
|
email = ["dep:aws-config"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
aws-config = { version = "0.55.1", optional = true }
|
aws-config = { version = "0.55.1", optional = true }
|
||||||
@ -19,7 +20,12 @@ once_cell = "1.17.1"
|
|||||||
serde = { version = "1.0.160", features = ["derive"] }
|
serde = { version = "1.0.160", features = ["derive"] }
|
||||||
thiserror = "1.0.40"
|
thiserror = "1.0.40"
|
||||||
tokio = "1.27.0"
|
tokio = "1.27.0"
|
||||||
|
dyn-clone = "1.0.11"
|
||||||
|
async-trait = "0.1.66"
|
||||||
|
aws-sdk-sesv2 = "0.27.0"
|
||||||
|
aws-smithy-client = "0.55.0"
|
||||||
|
|
||||||
# First party crates
|
# First party crates
|
||||||
common_utils = { version = "0.1.0", path = "../common_utils" }
|
common_utils = { version = "0.1.0", path = "../common_utils" }
|
||||||
router_env = { version = "0.1.0", path = "../router_env", features = ["log_extra_implicit_fields", "log_custom_entries_to_extra"] }
|
router_env = { version = "0.1.0", path = "../router_env", features = ["log_extra_implicit_fields", "log_custom_entries_to_extra"] }
|
||||||
|
masking = { version = "0.1.0", path = "../masking" }
|
||||||
|
|||||||
123
crates/external_services/src/email.rs
Normal file
123
crates/external_services/src/email.rs
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
//! Interactions with the AWS SES SDK
|
||||||
|
|
||||||
|
use aws_config::meta::region::RegionProviderChain;
|
||||||
|
use aws_sdk_sesv2::{
|
||||||
|
config::Region,
|
||||||
|
operation::send_email::SendEmailError,
|
||||||
|
types::{Body, Content, Destination, EmailContent, Message},
|
||||||
|
Client,
|
||||||
|
};
|
||||||
|
use common_utils::{errors::CustomResult, pii};
|
||||||
|
use error_stack::{IntoReport, ResultExt};
|
||||||
|
use masking::PeekInterface;
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
/// Custom Result type alias for Email operations.
|
||||||
|
pub type EmailResult<T> = CustomResult<T, EmailError>;
|
||||||
|
|
||||||
|
/// A trait that defines the methods that must be implemented to send email.
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
pub trait EmailClient: Sync + Send + dyn_clone::DynClone {
|
||||||
|
/// Sends an email to the specified recipient with the given subject and body.
|
||||||
|
async fn send_email(
|
||||||
|
&self,
|
||||||
|
recipient: pii::Email,
|
||||||
|
subject: String,
|
||||||
|
body: String,
|
||||||
|
) -> EmailResult<()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
dyn_clone::clone_trait_object!(EmailClient);
|
||||||
|
|
||||||
|
/// Struct that contains the settings required to construct an EmailClient.
|
||||||
|
#[derive(Debug, Clone, Default, Deserialize)]
|
||||||
|
pub struct EmailSettings {
|
||||||
|
/// Sender email.
|
||||||
|
pub from_email: String,
|
||||||
|
|
||||||
|
/// The AWS region to send SES requests to.
|
||||||
|
pub aws_region: String,
|
||||||
|
|
||||||
|
/// Base-url used when adding links that should redirect to self
|
||||||
|
pub base_url: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Client for AWS SES operation
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct AwsSes {
|
||||||
|
ses_client: Client,
|
||||||
|
from_email: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AwsSes {
|
||||||
|
/// Constructs a new AwsSes client
|
||||||
|
pub async fn new(conf: &EmailSettings) -> Self {
|
||||||
|
let region_provider = RegionProviderChain::first_try(Region::new(conf.aws_region.clone()));
|
||||||
|
let sdk_config = aws_config::from_env().region(region_provider).load().await;
|
||||||
|
|
||||||
|
Self {
|
||||||
|
ses_client: Client::new(&sdk_config),
|
||||||
|
from_email: conf.from_email.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl EmailClient for AwsSes {
|
||||||
|
async fn send_email(
|
||||||
|
&self,
|
||||||
|
recipient: pii::Email,
|
||||||
|
subject: String,
|
||||||
|
body: String,
|
||||||
|
) -> EmailResult<()> {
|
||||||
|
self.ses_client
|
||||||
|
.send_email()
|
||||||
|
.from_email_address(self.from_email.to_owned())
|
||||||
|
.destination(
|
||||||
|
Destination::builder()
|
||||||
|
.to_addresses(recipient.peek())
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
|
.content(
|
||||||
|
EmailContent::builder()
|
||||||
|
.simple(
|
||||||
|
Message::builder()
|
||||||
|
.subject(Content::builder().data(subject).build())
|
||||||
|
.body(
|
||||||
|
Body::builder()
|
||||||
|
.text(Content::builder().data(body).charset("UTF-8").build())
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.map_err(AwsSesError::SendingFailure)
|
||||||
|
.into_report()
|
||||||
|
.change_context(EmailError::EmailSendingFailure)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Errors that could occur from EmailClient.
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum EmailError {
|
||||||
|
/// An error occurred when building email client.
|
||||||
|
#[error("Error building email client")]
|
||||||
|
ClientBuildingFailure,
|
||||||
|
|
||||||
|
/// An error occurred when sending email
|
||||||
|
#[error("Error sending email to recipient")]
|
||||||
|
EmailSendingFailure,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Errors that could occur during SES operations.
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum AwsSesError {
|
||||||
|
/// An error occurred in the SDK while sending email.
|
||||||
|
#[error("Failed to Send Email {0:?}")]
|
||||||
|
SendingFailure(aws_smithy_client::SdkError<SendEmailError>),
|
||||||
|
}
|
||||||
@ -3,6 +3,9 @@
|
|||||||
#![forbid(unsafe_code)]
|
#![forbid(unsafe_code)]
|
||||||
#![warn(missing_docs, missing_debug_implementations)]
|
#![warn(missing_docs, missing_debug_implementations)]
|
||||||
|
|
||||||
|
#[cfg(feature = "email")]
|
||||||
|
pub mod email;
|
||||||
|
|
||||||
#[cfg(feature = "kms")]
|
#[cfg(feature = "kms")]
|
||||||
pub mod kms;
|
pub mod kms;
|
||||||
|
|
||||||
|
|||||||
@ -13,10 +13,11 @@ build = "src/build.rs"
|
|||||||
default = ["kv_store", "stripe", "oltp", "olap", "accounts_cache", "dummy_connector"]
|
default = ["kv_store", "stripe", "oltp", "olap", "accounts_cache", "dummy_connector"]
|
||||||
s3 = ["dep:aws-sdk-s3","dep:aws-config"]
|
s3 = ["dep:aws-sdk-s3","dep:aws-config"]
|
||||||
kms = ["external_services/kms","dep:aws-config"]
|
kms = ["external_services/kms","dep:aws-config"]
|
||||||
|
email = ["external_services/email","dep:aws-config"]
|
||||||
basilisk = ["kms"]
|
basilisk = ["kms"]
|
||||||
stripe = ["dep:serde_qs"]
|
stripe = ["dep:serde_qs"]
|
||||||
sandbox = ["kms", "stripe", "basilisk", "s3"]
|
sandbox = ["kms", "stripe", "basilisk", "s3", "email"]
|
||||||
production = ["kms", "stripe", "basilisk", "s3"]
|
production = ["kms", "stripe", "basilisk", "s3", "email"]
|
||||||
olap = []
|
olap = []
|
||||||
oltp = []
|
oltp = []
|
||||||
kv_store = []
|
kv_store = []
|
||||||
|
|||||||
@ -7,6 +7,8 @@ use std::{
|
|||||||
use api_models::enums;
|
use api_models::enums;
|
||||||
use common_utils::ext_traits::ConfigExt;
|
use common_utils::ext_traits::ConfigExt;
|
||||||
use config::{Environment, File};
|
use config::{Environment, File};
|
||||||
|
#[cfg(feature = "email")]
|
||||||
|
use external_services::email::EmailSettings;
|
||||||
#[cfg(feature = "kms")]
|
#[cfg(feature = "kms")]
|
||||||
use external_services::kms;
|
use external_services::kms;
|
||||||
use redis_interface::RedisSettings;
|
use redis_interface::RedisSettings;
|
||||||
@ -69,6 +71,8 @@ pub struct Settings {
|
|||||||
pub connector_customer: ConnectorCustomer,
|
pub connector_customer: ConnectorCustomer,
|
||||||
#[cfg(feature = "dummy_connector")]
|
#[cfg(feature = "dummy_connector")]
|
||||||
pub dummy_connector: DummyConnector,
|
pub dummy_connector: DummyConnector,
|
||||||
|
#[cfg(feature = "email")]
|
||||||
|
pub email: EmailSettings,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Clone, Default)]
|
#[derive(Debug, Deserialize, Clone, Default)]
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
use actix_web::{web, Scope};
|
use actix_web::{web, Scope};
|
||||||
|
#[cfg(feature = "email")]
|
||||||
|
use external_services::email::{AwsSes, EmailClient};
|
||||||
use tokio::sync::oneshot;
|
use tokio::sync::oneshot;
|
||||||
|
|
||||||
#[cfg(feature = "dummy_connector")]
|
#[cfg(feature = "dummy_connector")]
|
||||||
@ -22,12 +24,16 @@ pub struct AppState {
|
|||||||
pub flow_name: String,
|
pub flow_name: String,
|
||||||
pub store: Box<dyn StorageInterface>,
|
pub store: Box<dyn StorageInterface>,
|
||||||
pub conf: Settings,
|
pub conf: Settings,
|
||||||
|
#[cfg(feature = "email")]
|
||||||
|
pub email_client: Box<dyn EmailClient>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait AppStateInfo {
|
pub trait AppStateInfo {
|
||||||
fn conf(&self) -> Settings;
|
fn conf(&self) -> Settings;
|
||||||
fn flow_name(&self) -> String;
|
fn flow_name(&self) -> String;
|
||||||
fn store(&self) -> Box<dyn StorageInterface>;
|
fn store(&self) -> Box<dyn StorageInterface>;
|
||||||
|
#[cfg(feature = "email")]
|
||||||
|
fn email_client(&self) -> Box<dyn EmailClient>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppStateInfo for AppState {
|
impl AppStateInfo for AppState {
|
||||||
@ -40,6 +46,10 @@ impl AppStateInfo for AppState {
|
|||||||
fn store(&self) -> Box<dyn StorageInterface> {
|
fn store(&self) -> Box<dyn StorageInterface> {
|
||||||
self.store.to_owned()
|
self.store.to_owned()
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "email")]
|
||||||
|
fn email_client(&self) -> Box<dyn EmailClient> {
|
||||||
|
self.email_client.to_owned()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppState {
|
impl AppState {
|
||||||
@ -56,10 +66,15 @@ impl AppState {
|
|||||||
StorageImpl::Mock => Box::new(MockDb::new(&conf).await),
|
StorageImpl::Mock => Box::new(MockDb::new(&conf).await),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(feature = "email")]
|
||||||
|
#[allow(clippy::expect_used)]
|
||||||
|
let email_client = Box::new(AwsSes::new(&conf.email).await);
|
||||||
Self {
|
Self {
|
||||||
flow_name: String::from("default"),
|
flow_name: String::from("default"),
|
||||||
store,
|
store,
|
||||||
conf,
|
conf,
|
||||||
|
#[cfg(feature = "email")]
|
||||||
|
email_client,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user