1 /** 2 * Copyright © DiamondMVC 2019 3 * License: MIT (https://github.com/DiamondMVC/Diamond/blob/master/LICENSE) 4 * Author: Jacob Jensen (bausshf) 5 */ 6 module diamond.mail.smtp; 7 8 import diamond.core.apptype; 9 10 static if (isWeb) 11 { 12 import vibe.d : SMTPClientSettings, SMTPAuthType, SMTPConnectionType, 13 TLSContext, TLSPeerValidationMode, TLSVersion, 14 Mail, sendMail; 15 16 import diamond.errors.checks; 17 import diamond.core.traits; 18 import diamond.security.validation.sensitive; 19 20 // Alias to SMTPAuthType. 21 mixin(createEnumAlias!SMTPAuthType("SmtpAuthType")); 22 23 // Alias to SMTPConnectionType. 24 mixin(createEnumAlias!SMTPConnectionType("SmtpConnectionType")); 25 26 /// Wrapper around smtp client settings. 27 final class SmtpClientSettings 28 { 29 private: 30 /// The raw vibe.d smtp settings. 31 SMTPClientSettings _settings; 32 33 /// Boolean determining whether the mail should allow sensitive data or not. 34 bool _allowSensitiveData; 35 36 public: 37 final: 38 /// Creates new smtp client settings. 39 this() 40 { 41 _settings = new SMTPClientSettings; 42 } 43 44 /** 45 * Creates new smtp client settings. 46 * Params: 47 * host = The host of the smtp server. 48 * port = The port of the smtp server. 49 */ 50 this(string host, ushort port) 51 { 52 _settings = new SMTPClientSettings(host, port); 53 } 54 55 /** 56 * Creates new smtp client settings. 57 * Params: 58 * host = The host of the smtp server. 59 * port = The port of the smtp server. 60 * username = The username to use for the authentication. 61 * password = The password to use for the authentication. 62 */ 63 this(string host, ushort port, string username, string password) 64 { 65 this(host, port); 66 67 this.username = username; 68 this.password = password; 69 } 70 71 @property 72 { 73 /// Gets the authentication type. 74 SmtpAuthType authType() { return cast(SmtpAuthType)_settings.authType; } 75 76 /// Sets the authentication type. 77 void authType(SmtpAuthType newAuthType) 78 { 79 _settings.authType = cast(SMTPAuthType)newAuthType; 80 } 81 82 /// Gets the connection type. 83 SmtpConnectionType connectionType() { return cast(SmtpConnectionType)_settings.connectionType; } 84 85 /// Sets the connection type. 86 void connectionType(SmtpConnectionType newConnectionType) 87 { 88 _settings.connectionType = cast(SMTPConnectionType)newConnectionType; 89 } 90 91 /// Gets the host. 92 string host() { return _settings.host; } 93 94 /// Sets the host. 95 void host(string newHost) 96 { 97 _settings.host = newHost; 98 } 99 100 /// Gets the local name. 101 string localName() { return _settings.localname; } 102 103 /// Sets the local name. 104 void localName(string newLocalName) 105 { 106 _settings.localname = newLocalName; 107 } 108 109 /// Gets the username for the authentication. 110 string username() { return _settings.username; } 111 112 /// Sets the username for the authentication. 113 void username(string newUsername) 114 { 115 _settings.username = newUsername; 116 } 117 118 /// Gets the password for the authentication. 119 string password() { return _settings.password; } 120 121 /// Sets the password for the authentication. 122 void password(string newPassword) 123 { 124 _settings.password = newPassword; 125 } 126 127 /// Gets the port. 128 ushort port() { return _settings.port; } 129 130 /// Sets the port. 131 void port(ushort newPort) 132 { 133 _settings.port = newPort; 134 } 135 136 /// Get the tls context setup. 137 void delegate(scope TLSContext) @safe tlsContextSetup() { return _settings.tlsContextSetup; } 138 139 /// Sets the tls context setup. 140 void tlsContextSetup(void delegate(scope TLSContext) @safe newContextSetup) 141 { 142 _settings.tlsContextSetup = newContextSetup; 143 } 144 145 /// Gets the tls validation mode. 146 TLSPeerValidationMode tlsValidationMode() { return _settings.tlsValidationMode; } 147 148 /// Sets the tls validation mode. 149 void tlsValidationMode(TLSPeerValidationMode newValidationMode) 150 { 151 _settings.tlsValidationMode = newValidationMode; 152 } 153 154 /// Gets the tls version. 155 TLSVersion tlsVersion() { return _settings.tlsVersion; } 156 157 /// Sets the tls version. 158 void tlsVersion(TLSVersion newVersion) 159 { 160 _settings.tlsVersion = newVersion; 161 } 162 163 /// Gets a boolean determining whether the mail should allow sensitive data or not. 164 bool allowSensitiveData() { return _allowSensitiveData; } 165 166 /// Sets a boolean determining whether the mail should allow sensitive data or not. 167 void allowSensitiveData(bool shouldAllowSensitiveData) 168 { 169 _allowSensitiveData = shouldAllowSensitiveData; 170 } 171 } 172 } 173 174 /// Wrapper around an smtp mail. 175 final class SmtpMail 176 { 177 private: 178 /// The raw vibe.d mail. 179 Mail _mail; 180 /// The smtp client settings. 181 SmtpClientSettings _settings; 182 /// The sender. 183 string _sender; 184 /// The from-mail. 185 string _fromMail; 186 /// The recipient; 187 string _recipient; 188 /// The subject. 189 string _subject; 190 /// The message. 191 string _message; 192 /// The content type. 193 string _contentType; 194 195 public: 196 final: 197 /// Creates a new mail. 198 this() 199 { 200 _mail = new Mail; 201 } 202 203 /** 204 * Creates a new mail. 205 * Params: 206 * settings = The settings for the mail. 207 */ 208 this(SmtpClientSettings settings) 209 { 210 _settings = settings; 211 } 212 213 @property 214 { 215 /// Gets the sender. 216 string sender() { return _sender; } 217 218 /// Sets the sender. 219 void sender(string newSender) 220 { 221 _sender = newSender; 222 } 223 224 /// Gets the from-mail. 225 string fromMail() { return _fromMail; } 226 227 /// Sets the from-mail. 228 void fromMail(string newFromMail) 229 { 230 _fromMail = newFromMail; 231 } 232 233 /// Gets the recipient. 234 string recipient() { return _recipient; } 235 236 /// Sets the recipient. 237 void recipient(string newRecipient) 238 { 239 _recipient = newRecipient; 240 } 241 242 /// Gets the subject. 243 string subject() { return _subject; } 244 245 /// Sets the subject. 246 void subject(string newSubject) 247 { 248 _subject = newSubject; 249 } 250 251 /// Gets the message. 252 string message() { return _message; } 253 254 /// Set the message. 255 void message(string newMessage) 256 { 257 _message = newMessage; 258 } 259 260 /// Gets the content type. 261 string contentType() { return _contentType; } 262 263 /// Sets the content type. 264 void contentType(string newContentType) 265 { 266 _contentType = newContentType; 267 } 268 } 269 270 /** 271 * Adds a header. 272 * Params: 273 * name = The name of the header. 274 * value = The value of the header. 275 */ 276 void addHeader(string name, string value) 277 { 278 _mail.headers[name] = value; 279 } 280 281 /** 282 * Sends a mail with the mails current settings. 283 * Params: 284 * level = The security level to use for sensitive data if validation is turned on. 285 */ 286 void send(SecurityLevel level = SecurityLevel.maximum) 287 { 288 enforce(_settings !is null, "The mail has no settings configured."); 289 290 send(_settings, level); 291 } 292 293 /** 294 * Sends a mail using specific settings. 295 * Params: 296 * settings = The settings to use. 297 * level = The security level to use for sensitive data if validation is turned on. 298 */ 299 void send(SmtpClientSettings settings, SecurityLevel level = SecurityLevel.maximum) 300 { 301 enforce(settings !is null, "Cannot send a mail without settings."); 302 303 enforce(_fromMail && _fromMail.length, "From-mail is missing."); 304 enforce(_recipient && _recipient.length, "Recipient is missing."); 305 enforce(_subject && _subject.length, "Subject is missing."); 306 enforce(_message && _message.length, "Message is missing."); 307 308 if (!settings.allowSensitiveData) 309 { 310 validateSensitiveData(_message, level); 311 } 312 313 if (_sender && _sender.length) 314 { 315 addHeader("Sender", _sender); 316 } 317 318 addHeader("From", _fromMail); 319 addHeader("To", _recipient); 320 addHeader("Subject", _subject); 321 322 _mail.bodyText = _message; 323 324 addHeader( 325 "Content-Type", 326 _contentType && _contentType.length ? 327 _contentType : "text/plain;charset=utf-8" 328 ); 329 330 sendMail(settings._settings, _mail); 331 } 332 } 333 }