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