diff --git a/.spi.yml b/.spi.yml
index 8a3fa63..b5ab714 100644
--- a/.spi.yml
+++ b/.spi.yml
@@ -1,5 +1,4 @@
version: 1
builder:
configs:
- - documentation_targets: [SendGridKit]
- swift_version: 6.0
\ No newline at end of file
+ - documentation_targets: [SendGridKit]
\ No newline at end of file
diff --git a/.swift-format b/.swift-format
new file mode 100644
index 0000000..47901d1
--- /dev/null
+++ b/.swift-format
@@ -0,0 +1,70 @@
+{
+ "fileScopedDeclarationPrivacy": {
+ "accessLevel": "private"
+ },
+ "indentation": {
+ "spaces": 4
+ },
+ "indentConditionalCompilationBlocks": true,
+ "indentSwitchCaseLabels": false,
+ "lineBreakAroundMultilineExpressionChainComponents": false,
+ "lineBreakBeforeControlFlowKeywords": false,
+ "lineBreakBeforeEachArgument": false,
+ "lineBreakBeforeEachGenericRequirement": false,
+ "lineLength": 140,
+ "maximumBlankLines": 1,
+ "multiElementCollectionTrailingCommas": true,
+ "noAssignmentInExpressions": {
+ "allowedFunctions": [
+ "XCTAssertNoThrow"
+ ]
+ },
+ "prioritizeKeepingFunctionOutputTogether": false,
+ "respectsExistingLineBreaks": true,
+ "rules": {
+ "AllPublicDeclarationsHaveDocumentation": false,
+ "AlwaysUseLiteralForEmptyCollectionInit": false,
+ "AlwaysUseLowerCamelCase": true,
+ "AmbiguousTrailingClosureOverload": true,
+ "BeginDocumentationCommentWithOneLineSummary": false,
+ "DoNotUseSemicolons": true,
+ "DontRepeatTypeInStaticProperties": true,
+ "FileScopedDeclarationPrivacy": true,
+ "FullyIndirectEnum": true,
+ "GroupNumericLiterals": true,
+ "IdentifiersMustBeASCII": true,
+ "NeverForceUnwrap": false,
+ "NeverUseForceTry": false,
+ "NeverUseImplicitlyUnwrappedOptionals": false,
+ "NoAccessLevelOnExtensionDeclaration": true,
+ "NoAssignmentInExpressions": true,
+ "NoBlockComments": true,
+ "NoCasesWithOnlyFallthrough": true,
+ "NoEmptyTrailingClosureParentheses": true,
+ "NoLabelsInCasePatterns": true,
+ "NoLeadingUnderscores": false,
+ "NoParensAroundConditions": true,
+ "NoPlaygroundLiterals": true,
+ "NoVoidReturnOnFunctionSignature": true,
+ "OmitExplicitReturns": false,
+ "OneCasePerLine": true,
+ "OneVariableDeclarationPerLine": true,
+ "OnlyOneTrailingClosureArgument": true,
+ "OrderedImports": true,
+ "ReplaceForEachWithForLoop": true,
+ "ReturnVoidInsteadOfEmptyTuple": true,
+ "TypeNamesShouldBeCapitalized": true,
+ "UseEarlyExits": false,
+ "UseExplicitNilCheckInConditions": true,
+ "UseLetInEveryBoundCaseVariable": true,
+ "UseShorthandTypeNames": true,
+ "UseSingleLinePropertyGetter": true,
+ "UseSynthesizedInitializer": true,
+ "UseTripleSlashForDocumentationComments": true,
+ "UseWhereClausesInForLoops": false,
+ "ValidateDocumentationComments": false
+ },
+ "spacesAroundRangeFormationOperators": false,
+ "tabWidth": 8,
+ "version": 1
+}
\ No newline at end of file
diff --git a/README.md b/README.md
index 2ba597c..8719c41 100644
--- a/README.md
+++ b/README.md
@@ -18,22 +18,22 @@
-📧 SendGridKit is a Swift package used to communicate with the SendGrid API for Server Side Swift Apps.
+📧 SendGridKit is a Swift package that helps you communicate with the SendGrid API in your Server Side Swift applications.
-Send simple emails, or leverage the full capabilities of [SendGrid's V3 API](https://www.twilio.com/docs/sendgrid/api-reference/mail-send/mail-send).
+Send simple emails or leverage the full capabilities of [SendGrid's V3 API](https://www.twilio.com/docs/sendgrid/api-reference/mail-send/mail-send).
### Getting Started
Use the SPM string to easily include the dependendency in your `Package.swift` file
```swift
-.package(url: "https://github.com/vapor-community/sendgrid-kit.git", from: "3.0.0-rc.1")
+.package(url: "https://github.com/vapor-community/sendgrid-kit.git", from: "3.0.0"),
```
and add it to your target's dependencies:
```swift
-.product(name: "SendGridKit", package: "sendgrid-kit")
+.product(name: "SendGridKit", package: "sendgrid-kit"),
```
## Overview
@@ -41,6 +41,9 @@ and add it to your target's dependencies:
Register the config and the provider.
```swift
+import AsyncHTTPClient
+import SendGridKit
+
let httpClient = HTTPClient(...)
let sendGridClient = SendGridClient(httpClient: httpClient, apiKey: "YOUR_API_KEY")
```
@@ -65,6 +68,8 @@ If the request to the API failed for any reason a `SendGridError` is thrown, whi
Simply ensure you catch errors thrown like any other throwing function.
```swift
+import SendGridKit
+
do {
try await sendGridClient.send(email: email)
} catch let error as SendGridError {
diff --git a/Sources/SendGridKit/Models/AdvancedSuppressionManager.swift b/Sources/SendGridKit/Models/AdvancedSuppressionManager.swift
index 5a213db..cd0b381 100644
--- a/Sources/SendGridKit/Models/AdvancedSuppressionManager.swift
+++ b/Sources/SendGridKit/Models/AdvancedSuppressionManager.swift
@@ -1,5 +1,6 @@
import Foundation
+/// An object allowing you to specify how to handle unsubscribes.
public struct AdvancedSuppressionManager: Codable, Sendable {
/// The unsubscribe group to associate with this email.
///
diff --git a/Sources/SendGridKit/Models/EmailAddress.swift b/Sources/SendGridKit/Models/EmailAddress.swift
index 439e7f7..ef70e30 100644
--- a/Sources/SendGridKit/Models/EmailAddress.swift
+++ b/Sources/SendGridKit/Models/EmailAddress.swift
@@ -1,5 +1,6 @@
import Foundation
+/// An email address to use in an email to be sent via the SendGrid API.
public struct EmailAddress: Codable, Sendable {
/// The email address of the person to whom you are sending an email.
public var email: String
diff --git a/Sources/SendGridKit/Models/EmailAttachment.swift b/Sources/SendGridKit/Models/EmailAttachment.swift
index c2c8027..58a7d8f 100644
--- a/Sources/SendGridKit/Models/EmailAttachment.swift
+++ b/Sources/SendGridKit/Models/EmailAttachment.swift
@@ -1,5 +1,6 @@
import Foundation
+/// An attachment to include in an email.
public struct EmailAttachment: Codable, Sendable {
/// The Base64 encoded content of the attachment.
public var content: String
@@ -19,8 +20,12 @@ public struct EmailAttachment: Codable, Sendable {
/// such as opening or downloading the file.
public var disposition: Disposition?
+ /// The disposition of the attachment.
public enum Disposition: String, Codable, Sendable {
+ /// The attachment is displayed automatically within the message.
case inline
+
+ /// The attached file requires some action to be taken before it is displayed.
case attachment
}
diff --git a/Sources/SendGridKit/Models/EmailContent.swift b/Sources/SendGridKit/Models/EmailContent.swift
index c0d5f41..0d2df9d 100644
--- a/Sources/SendGridKit/Models/EmailContent.swift
+++ b/Sources/SendGridKit/Models/EmailContent.swift
@@ -1,5 +1,6 @@
import Foundation
+/// The content of an email.
public struct EmailContent: Codable, Sendable {
/// The MIME type of the content you are including in your email.
///
diff --git a/Sources/SendGridKit/Models/MailSettings.swift b/Sources/SendGridKit/Models/MailSettings.swift
index 7233d48..597da2f 100644
--- a/Sources/SendGridKit/Models/MailSettings.swift
+++ b/Sources/SendGridKit/Models/MailSettings.swift
@@ -1,5 +1,6 @@
import Foundation
+/// Advanced settings to control how you would like to handle the email.
public struct MailSettings: Codable, Sendable {
/// Allows you to bypass all unsubscribe groups and suppressions to ensure that the email is delivered to every single recipient.
///
@@ -47,32 +48,44 @@ public struct MailSettings: Codable, Sendable {
}
}
-public struct Setting: Codable, Sendable {
- /// Indicates if this setting is enabled.
- public var enable: Bool
+extension MailSettings {
+ /// Indicates if a setting of ``MailSettings`` is enabled.
+ public struct Setting: Codable, Sendable, ExpressibleByBooleanLiteral {
+ /// Indicates if this setting is enabled.
+ public var enable: Bool
- public init(enable: Bool) {
- self.enable = enable
+ public init(enable: Bool) {
+ self.enable = enable
+ }
+
+ public init(booleanLiteral value: Bool) {
+ self.init(enable: value)
+ }
}
-}
-public struct Footer: Codable, Sendable {
- /// Indicates if this setting is enabled.
- public var enable: Bool
+ /// The default footer that you would like included on every email.
+ public struct Footer: Codable, Sendable, ExpressibleByBooleanLiteral {
+ /// Indicates if this setting is enabled.
+ public var enable: Bool
+
+ /// The plain text content of your footer.
+ public var text: String?
- /// The plain text content of your footer.
- public var text: String?
+ /// The HTML content of your footer.
+ public var html: String?
- /// The HTML content of your footer.
- public var html: String?
+ public init(
+ enable: Bool,
+ text: String? = nil,
+ html: String? = nil
+ ) {
+ self.enable = enable
+ self.text = text
+ self.html = html
+ }
- public init(
- enable: Bool,
- text: String? = nil,
- html: String? = nil
- ) {
- self.enable = enable
- self.text = text
- self.html = html
+ public init(booleanLiteral value: Bool) {
+ self.init(enable: value)
+ }
}
}
diff --git a/Sources/SendGridKit/Models/Personalization.swift b/Sources/SendGridKit/Models/Personalization.swift
index 66abe9e..11aceaa 100644
--- a/Sources/SendGridKit/Models/Personalization.swift
+++ b/Sources/SendGridKit/Models/Personalization.swift
@@ -1,5 +1,6 @@
import Foundation
+/// An object containing the personalization of an email.
public struct Personalization: Codable, Sendable {
/// An array of recipients.
///
diff --git a/Sources/SendGridKit/Models/SendGridEmail.swift b/Sources/SendGridKit/Models/SendGridEmail.swift
index aff8657..e96f907 100644
--- a/Sources/SendGridKit/Models/SendGridEmail.swift
+++ b/Sources/SendGridKit/Models/SendGridEmail.swift
@@ -1,5 +1,6 @@
import Foundation
+/// An email to be sent using the SendGrid API.
public struct SendGridEmail: Codable, Sendable {
/// An array of messages and their metadata.
///
@@ -78,6 +79,7 @@ public struct SendGridEmail: Codable, S
/// Settings to determine how you would like to track the metrics of how your recipients interact with your email.
public var trackingSettings: TrackingSettings?
+ /// Initialize a new ``SendGridEmail`` using a custom dynamic template data type.
public init(
personalizations: [Personalization],
from: EmailAddress,
@@ -138,6 +140,7 @@ public struct SendGridEmail: Codable, S
}
extension SendGridEmail where DynamicTemplateData == [String: String] {
+ /// Initialize a new ``SendGridEmail`` using a dictionary of `String` as dynamic template data.
public init(
personalizations: [Personalization<[String: String]>],
from: EmailAddress,
diff --git a/Sources/SendGridKit/Models/SendGridError.swift b/Sources/SendGridKit/Models/SendGridError.swift
index 64a1fdf..fad77fd 100644
--- a/Sources/SendGridKit/Models/SendGridError.swift
+++ b/Sources/SendGridKit/Models/SendGridError.swift
@@ -1,19 +1,22 @@
import Foundation
+/// An error response from the SendGrid API.
public struct SendGridError: Error, Decodable, Sendable {
- public var errors: [SendGridErrorResponse]?
+ /// The errors returned by the SendGrid API.
+ public var errors: [Description]?
/// When applicable, this property value will be an error ID.
public var id: String?
-}
-public struct SendGridErrorResponse: Decodable, Sendable {
- /// An error message.
- public var message: String?
+ /// The description of the ``SendGridError``.
+ public struct Description: Decodable, Sendable {
+ /// An error message.
+ public var message: String?
- /// When applicable, this property value will be the field that generated the error.
- public var field: String?
+ /// When applicable, this property value will be the field that generated the error.
+ public var field: String?
- /// When applicable, this property value will be helper text or a link to documentation to help you troubleshoot the error.
- public var help: String?
+ /// When applicable, this property value will be helper text or a link to documentation to help you troubleshoot the error.
+ public var help: String?
+ }
}
diff --git a/Sources/SendGridKit/Models/TrackingSettings.swift b/Sources/SendGridKit/Models/TrackingSettings.swift
index 7cc1537..2f60022 100644
--- a/Sources/SendGridKit/Models/TrackingSettings.swift
+++ b/Sources/SendGridKit/Models/TrackingSettings.swift
@@ -1,5 +1,6 @@
import Foundation
+/// Settings to enable tracking for your email.
public struct TrackingSettings: Codable, Sendable {
/// Allows you to track whether a recipient clicked a link in your email.
public var clickTracking: ClickTracking?
@@ -38,130 +39,142 @@ public struct TrackingSettings: Codable, Sendable {
}
}
-public struct ClickTracking: Codable, Sendable {
- /// Indicates if this setting is enabled.
- public var enable: Bool
-
- /// Indicates if this setting should be included in the text/plain portion of your email.
- public var enableText: Bool
-
- public init(enable: Bool, enableText: Bool) {
- self.enable = enable
- self.enableText = enableText
+extension TrackingSettings {
+ /// Allows you to track whether a recipient clicked a link in your email.
+ public struct ClickTracking: Codable, Sendable {
+ /// Indicates if this setting is enabled.
+ public var enable: Bool
+
+ /// Indicates if this setting should be included in the text/plain portion of your email.
+ public var enableText: Bool
+
+ public init(enable: Bool, enableText: Bool) {
+ self.enable = enable
+ self.enableText = enableText
+ }
+
+ private enum CodingKeys: String, CodingKey {
+ case enable
+ case enableText = "enable_text"
+ }
}
- private enum CodingKeys: String, CodingKey {
- case enable
- case enableText = "enable_text"
- }
-}
-
-public struct OpenTracking: Codable, Sendable {
- /// Indicates if this setting is enabled.
- public var enable: Bool
-
- /// Allows you to specify a substitution tag that you can insert in the body of your email at a location that you desire.
+ /// Allows you to track if the email was opened by including a single transparent pixel image in the body of the message content.
///
- /// > Note: This tag will be replaced by the open tracking pixel.
- public var substitutionTag: String?
-
- public init(
- enable: Bool,
- substitutionTag: String? = nil
- ) {
- self.enable = enable
- self.substitutionTag = substitutionTag
+ /// When the message is opened, a request for the pixel is sent.
+ /// That request indicates to Twilio SendGrid that the message was opened.
+ public struct OpenTracking: Codable, Sendable {
+ /// Indicates if this setting is enabled.
+ public var enable: Bool
+
+ /// Allows you to specify a substitution tag that you can insert in the body of your email at a location that you desire.
+ ///
+ /// > Note: This tag will be replaced by the open tracking pixel.
+ public var substitutionTag: String?
+
+ public init(
+ enable: Bool,
+ substitutionTag: String? = nil
+ ) {
+ self.enable = enable
+ self.substitutionTag = substitutionTag
+ }
+
+ private enum CodingKeys: String, CodingKey {
+ case enable
+ case substitutionTag = "substitution_tag"
+ }
}
- private enum CodingKeys: String, CodingKey {
- case enable
- case substitutionTag = "substitution_tag"
- }
-}
-
-public struct SubscriptionTracking: Codable, Sendable {
- /// Indicates if this setting is enabled.
- public var enable: Bool
-
- /// Text to be appended to the email, with the subscription tracking link.
- ///
- /// > Tip: You may control where the link is by using the tag `<% %>`.
- public var text: String?
-
- /// HTML to be appended to the email, with the subscription tracking link.
- ///
- /// > Tip: You may control where the link is by using the tag `<% %>`.
- public var html: String?
-
- /// A tag that will be replaced with the unsubscribe URL.
- ///
- /// For example: `[unsubscribe_url]`.
+ /// Allows you to insert a subscription management link at the bottom of the text and HTML bodies of your email.
///
- /// If this parameter is used, it will override both the ``SubscriptionTracking/text`` and ``SubscriptionTracking/html`` parameters.
- /// The URL of the link will be placed at the substitution tag’s location, with no additional formatting.
- public var substitutionTag: String?
-
- public init(
- enable: Bool,
- text: String? = nil,
- html: String? = nil,
- substitutionTag: String? = nil
- ) {
- self.enable = enable
- self.text = text
- self.html = html
- self.substitutionTag = substitutionTag
- }
-
- private enum CodingKeys: String, CodingKey {
- case enable
- case text
- case html
- case substitutionTag = "substitution_tag"
- }
-}
-
-public struct GoogleAnalytics: Codable, Sendable {
- /// Indicates if this setting is enabled.
- public var enable: Bool
-
- /// Name of the referrer source. (e.g. Google, SomeDomain.com, or Marketing Email)
- public var utmSource: String?
-
- /// Name of the marketing medium. (e.g. Email)
- public var utmMedium: String?
-
- /// Used to identify any paid keywords.
- public var utmTerm: String?
-
- /// Used to differentiate your campaign from advertisements.
- public var utmContent: String?
-
- /// The name of the campaign.
- public var utmCampaign: String?
-
- public init(
- enable: Bool,
- utmSource: String? = nil,
- utmMedium: String? = nil,
- utmTerm: String? = nil,
- utmContent: String? = nil,
- utmCampaign: String? = nil
- ) {
- self.enable = enable
- self.utmSource = utmSource
- self.utmMedium = utmMedium
- self.utmTerm = utmTerm
- self.utmContent = utmContent
- self.utmCampaign = utmCampaign
+ /// If you would like to specify the location of the link within your email,
+ /// you may use the ``TrackingSettings/SubscriptionTracking/substitutionTag`` property.
+ public struct SubscriptionTracking: Codable, Sendable {
+ /// Indicates if this setting is enabled.
+ public var enable: Bool
+
+ /// Text to be appended to the email, with the subscription tracking link.
+ ///
+ /// > Tip: You may control where the link is by using the tag `<% %>`.
+ public var text: String?
+
+ /// HTML to be appended to the email, with the subscription tracking link.
+ ///
+ /// > Tip: You may control where the link is by using the tag `<% %>`.
+ public var html: String?
+
+ /// A tag that will be replaced with the unsubscribe URL.
+ ///
+ /// For example: `[unsubscribe_url]`.
+ ///
+ /// If this parameter is used, it will override both the ``SubscriptionTracking/text`` and ``SubscriptionTracking/html`` parameters.
+ /// The URL of the link will be placed at the substitution tag’s location, with no additional formatting.
+ public var substitutionTag: String?
+
+ public init(
+ enable: Bool,
+ text: String? = nil,
+ html: String? = nil,
+ substitutionTag: String? = nil
+ ) {
+ self.enable = enable
+ self.text = text
+ self.html = html
+ self.substitutionTag = substitutionTag
+ }
+
+ private enum CodingKeys: String, CodingKey {
+ case enable
+ case text
+ case html
+ case substitutionTag = "substitution_tag"
+ }
}
- private enum CodingKeys: String, CodingKey {
- case enable
- case utmSource = "utm_source"
- case utmMedium = "utm_medium"
- case utmTerm = "utm_term"
- case utmContent = "utm_content"
- case utmCampaign = "utm_campaign"
+ /// Allows you to enable tracking provided by Google Analytics.
+ public struct GoogleAnalytics: Codable, Sendable {
+ /// Indicates if this setting is enabled.
+ public var enable: Bool
+
+ /// Name of the referrer source. (e.g. Google, SomeDomain.com, or Marketing Email)
+ public var utmSource: String?
+
+ /// Name of the marketing medium. (e.g. Email)
+ public var utmMedium: String?
+
+ /// Used to identify any paid keywords.
+ public var utmTerm: String?
+
+ /// Used to differentiate your campaign from advertisements.
+ public var utmContent: String?
+
+ /// The name of the campaign.
+ public var utmCampaign: String?
+
+ public init(
+ enable: Bool,
+ utmSource: String? = nil,
+ utmMedium: String? = nil,
+ utmTerm: String? = nil,
+ utmContent: String? = nil,
+ utmCampaign: String? = nil
+ ) {
+ self.enable = enable
+ self.utmSource = utmSource
+ self.utmMedium = utmMedium
+ self.utmTerm = utmTerm
+ self.utmContent = utmContent
+ self.utmCampaign = utmCampaign
+ }
+
+ private enum CodingKeys: String, CodingKey {
+ case enable
+ case utmSource = "utm_source"
+ case utmMedium = "utm_medium"
+ case utmTerm = "utm_term"
+ case utmContent = "utm_content"
+ case utmCampaign = "utm_campaign"
+ }
}
}
diff --git a/Sources/SendGridKit/SendGridClient.swift b/Sources/SendGridKit/SendGridClient.swift
index 3161664..5e4f599 100644
--- a/Sources/SendGridKit/SendGridClient.swift
+++ b/Sources/SendGridKit/SendGridClient.swift
@@ -4,10 +4,11 @@ import NIO
import NIOFoundationCompat
import NIOHTTP1
+/// A client for sending emails using the SendGrid API.
public struct SendGridClient: Sendable {
- let apiURL: String
- let httpClient: HTTPClient
- let apiKey: String
+ private let apiURL: String
+ private let httpClient: HTTPClient
+ private let apiKey: String
private let encoder: JSONEncoder = {
let encoder = JSONEncoder()
@@ -33,6 +34,9 @@ public struct SendGridClient: Sendable {
self.apiURL = forEU ? "https://api.eu.sendgrid.com/v3/mail/send" : "https://api.sendgrid.com/v3/mail/send"
}
+ /// Send an email using the SendGrid API.
+ ///
+ /// - Parameter email: The ``SendGridEmail`` to send.
public func send(email: SendGridEmail) async throws {
var headers = HTTPHeaders()
headers.add(name: "Authorization", value: "Bearer \(self.apiKey)")
@@ -49,6 +53,6 @@ public struct SendGridClient: Sendable {
if (200...299).contains(response.status.code) { return }
// `JSONDecoder` will handle empty body by throwing decoding error
- throw try await decoder.decode(SendGridError.self, from: response.body.collect(upTo: 1024 * 1024))
+ throw try await self.decoder.decode(SendGridError.self, from: response.body.collect(upTo: 1024 * 1024))
}
}
diff --git a/Sources/SendGridKit/SendGridKit.docc/Extensions/SendGridClient.md b/Sources/SendGridKit/SendGridKit.docc/Extensions/SendGridClient.md
new file mode 100644
index 0000000..0360428
--- /dev/null
+++ b/Sources/SendGridKit/SendGridKit.docc/Extensions/SendGridClient.md
@@ -0,0 +1,42 @@
+# ``SendGridKit/SendGridClient``
+
+## Overview
+
+Register the config and the provider.
+
+```swift
+import AsyncHTTPClient
+import SendGridKit
+
+let httpClient = HTTPClient(...)
+let sendGridClient = SendGridClient(httpClient: httpClient, apiKey: "YOUR_API_KEY")
+```
+
+### Using the API
+
+You can use all of the available parameters here to build your ``SendGridEmail``.
+
+Usage in a route closure would be as followed:
+
+```swift
+import SendGridKit
+
+let email = SendGridEmail(...)
+try await sendGridClient.send(email: email)
+```
+
+### Error handling
+
+If the request to the API failed for any reason a ``SendGridError`` is thrown, which has an ``SendGridError/errors`` property that contains an array of errors returned by the API.
+
+Simply ensure you catch errors thrown like any other throwing function.
+
+```swift
+import SendGridKit
+
+do {
+ try await sendGridClient.send(email: email)
+} catch let error as SendGridError {
+ print(error)
+}
+```
diff --git a/Sources/SendGridKit/SendGridKit.docc/SendGridKit.md b/Sources/SendGridKit/SendGridKit.docc/SendGridKit.md
index 3be4880..9d7fc2b 100644
--- a/Sources/SendGridKit/SendGridKit.docc/SendGridKit.md
+++ b/Sources/SendGridKit/SendGridKit.docc/SendGridKit.md
@@ -1,42 +1,12 @@
# ``SendGridKit``
-📧 SendGridKit is a Swift package used to communicate with the SendGrid API for Server Side Swift Apps.
+A Swift on Server SDK for the SendGrid API
## Overview
-Register the config and the provider.
+`SendGridKit` is a Swift package that helps you communicate with the SendGrid API in your Server Side Swift applications.
-```swift
-let httpClient = HTTPClient(...)
-let sendGridClient = SendGridClient(httpClient: httpClient, apiKey: "YOUR_API_KEY")
-```
-
-### Using the API
-
-You can use all of the available parameters here to build your ``SendGridEmail``.
-
-Usage in a route closure would be as followed:
-
-```swift
-import SendGridKit
-
-let email = SendGridEmail(...)
-try await sendGridClient.send(email: email)
-```
-
-### Error handling
-
-If the request to the API failed for any reason a ``SendGridError`` is thrown, which has an ``SendGridError/errors`` property that contains an array of errors returned by the API.
-
-Simply ensure you catch errors thrown like any other throwing function.
-
-```swift
-do {
- try await sendGridClient.send(email: email)
-} catch let error as SendGridError {
- print(error)
-}
-```
+Send simple emails or leverage the full capabilities of [SendGrid's V3 API](https://www.twilio.com/docs/sendgrid/api-reference/mail-send/mail-send).
## Topics
@@ -47,6 +17,13 @@ do {
- ``Personalization``
- ``EmailAddress``
- ``EmailContent``
+- ``EmailAttachment``
+
+### Advanced
+
+- ``MailSettings``
+- ``TrackingSettings``
+- ``AdvancedSuppressionManager``
### Errors
diff --git a/Tests/SendGridKitTests/SendGridTestsKit.swift b/Tests/SendGridKitTests/SendGridKitTests.swift
similarity index 77%
rename from Tests/SendGridKitTests/SendGridTestsKit.swift
rename to Tests/SendGridKitTests/SendGridKitTests.swift
index 954a1f1..6982a0a 100644
--- a/Tests/SendGridKitTests/SendGridTestsKit.swift
+++ b/Tests/SendGridKitTests/SendGridKitTests.swift
@@ -2,15 +2,19 @@ import AsyncHTTPClient
import SendGridKit
import Testing
+@Suite("SendGridKit Tests")
struct SendGridKitTests {
var client: SendGridClient
+ // TODO: Replace with `false` when you have a valid API key
+ let credentialsAreInvalid = true
init() {
// TODO: Replace with a valid API key to test
client = SendGridClient(httpClient: HTTPClient.shared, apiKey: "YOUR-API-KEY")
}
- @Test func sendEmail() async throws {
+ @Test("Send Email")
+ func sendEmail() async throws {
// TODO: Replace to address with the email address you'd like to recieve your test email
let emailAddress = EmailAddress("TO-ADDRESS")
// TODO: Replace from address with the email address associated with your verified Sender Identity
@@ -27,25 +31,24 @@ struct SendGridKitTests {
let emailContent = EmailContent("This email was sent using SendGridKit!")
- let setting = Setting(enable: true)
let mailSettings = MailSettings(
- bypassListManagement: setting,
- bypassSpamManagement: setting,
- bypassBounceManagement: setting,
- footer: Footer(enable: true, text: "footer", html: "footer"),
- sandboxMode: setting
+ bypassListManagement: true,
+ bypassSpamManagement: true,
+ bypassBounceManagement: true,
+ footer: false,
+ sandboxMode: true
)
let trackingSettings = TrackingSettings(
- clickTracking: ClickTracking(enable: true, enableText: true),
- openTracking: OpenTracking(enable: true, substitutionTag: "open_tracking"),
- subscriptionTracking: SubscriptionTracking(
+ clickTracking: .init(enable: true, enableText: true),
+ openTracking: .init(enable: true, substitutionTag: "open_tracking"),
+ subscriptionTracking: .init(
enable: true,
text: "sub_text",
html: "sub_html",
substitutionTag: "sub_tag"
),
- ganalytics: GoogleAnalytics(
+ ganalytics: .init(
enable: true,
utmSource: "utm_source",
utmMedium: "utm_medium",
@@ -70,12 +73,12 @@ struct SendGridKitTests {
try await withKnownIssue {
try await client.send(email: email)
} when: {
- // TODO: Replace with `false` when you have a valid API key
- true
+ credentialsAreInvalid
}
}
- @Test func dynamicTemplateData() async throws {
+ @Test("DynamicTemplateData")
+ func dynamicTemplateData() async throws {
struct DynamicTemplateData: Codable, Sendable {
let text: String
let integer: Int
@@ -96,8 +99,7 @@ struct SendGridKitTests {
try await withKnownIssue {
try await client.send(email: email)
} when: {
- // TODO: Replace with `false` when you have a valid API key
- true
+ credentialsAreInvalid
}
}
}