1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.commons.net.smtp;
17
18 import java.io.BufferedReader;
19 import java.io.BufferedWriter;
20 import java.io.IOException;
21 import java.io.InputStreamReader;
22 import java.io.OutputStreamWriter;
23 import java.util.Enumeration;
24 import java.util.Vector;
25 import org.apache.commons.net.MalformedServerReplyException;
26 import org.apache.commons.net.ProtocolCommandListener;
27 import org.apache.commons.net.ProtocolCommandSupport;
28 import org.apache.commons.net.SocketClient;
29
30 /***
31 * SMTP provides the basic the functionality necessary to implement your
32 * own SMTP client. To derive the full benefits of the SMTP class requires
33 * some knowledge of the FTP protocol defined in RFC 821. However, there
34 * is no reason why you should have to use the SMTP class. The
35 * {@link org.apache.commons.net.smtp.SMTPClient} class,
36 * derived from SMTP,
37 * implements all the functionality required of an SMTP client. The
38 * SMTP class is made public to provide access to various SMTP constants
39 * and to make it easier for adventurous programmers (or those with
40 * special needs) to interact with the SMTP protocol and implement their
41 * own clients. A set of methods with names corresponding to the SMTP
42 * command names are provided to facilitate this interaction.
43 * <p>
44 * You should keep in mind that the SMTP server may choose to prematurely
45 * close a connection for various reasons. The SMTP class will detect a
46 * premature SMTP server connection closing when it receives a
47 * {@link org.apache.commons.net.smtp.SMTPReply#SERVICE_NOT_AVAILABLE SMTPReply.SERVICE_NOT_AVAILABLE }
48 * response to a command.
49 * When that occurs, the SMTP class method encountering that reply will throw
50 * an {@link org.apache.commons.net.smtp.SMTPConnectionClosedException}
51 * .
52 * <code>SMTPConectionClosedException</code>
53 * is a subclass of <code> IOException </code> and therefore need not be
54 * caught separately, but if you are going to catch it separately, its
55 * catch block must appear before the more general <code> IOException </code>
56 * catch block. When you encounter an
57 * {@link org.apache.commons.net.smtp.SMTPConnectionClosedException}
58 * , you must disconnect the connection with
59 * {@link org.apache.commons.net.SocketClient#disconnect disconnect() }
60 * to properly clean up the system resources used by SMTP. Before
61 * disconnecting, you may check the
62 * last reply code and text with
63 * {@link #getReplyCode getReplyCode },
64 * {@link #getReplyString getReplyString },
65 * and {@link #getReplyStrings getReplyStrings}.
66 * <p>
67 * Rather than list it separately for each method, we mention here that
68 * every method communicating with the server and throwing an IOException
69 * can also throw a
70 * {@link org.apache.commons.net.MalformedServerReplyException}
71 * , which is a subclass
72 * of IOException. A MalformedServerReplyException will be thrown when
73 * the reply received from the server deviates enough from the protocol
74 * specification that it cannot be interpreted in a useful manner despite
75 * attempts to be as lenient as possible.
76 * <p>
77 * <p>
78 * @author Daniel F. Savarese
79 * @see SMTPClient
80 * @see SMTPConnectionClosedException
81 * @see org.apache.commons.net.MalformedServerReplyException
82 ***/
83
84 public class SMTP extends SocketClient
85 {
86 /*** The default SMTP port (25). ***/
87 public static final int DEFAULT_PORT = 25;
88
89
90
91
92 private static final String __DEFAULT_ENCODING = "ISO-8859-1";
93
94 private StringBuffer __commandBuffer;
95
96 BufferedReader _reader;
97 BufferedWriter _writer;
98 int _replyCode;
99 Vector _replyLines;
100 boolean _newReplyString;
101 String _replyString;
102
103 /***
104 * A ProtocolCommandSupport object used to manage the registering of
105 * ProtocolCommandListeners and te firing of ProtocolCommandEvents.
106 ***/
107 protected ProtocolCommandSupport _commandSupport_;
108
109 /***
110 * The default SMTP constructor. Sets the default port to
111 * <code>DEFAULT_PORT</code> and initializes internal data structures
112 * for saving SMTP reply information.
113 ***/
114 public SMTP()
115 {
116 setDefaultPort(DEFAULT_PORT);
117 __commandBuffer = new StringBuffer();
118 _replyLines = new Vector();
119 _newReplyString = false;
120 _replyString = null;
121 _commandSupport_ = new ProtocolCommandSupport(this);
122 }
123
124 private int __sendCommand(String command, String args, boolean includeSpace)
125 throws IOException
126 {
127 String message;
128
129 __commandBuffer.setLength(0);
130 __commandBuffer.append(command);
131
132 if (args != null)
133 {
134 if (includeSpace)
135 __commandBuffer.append(' ');
136 __commandBuffer.append(args);
137 }
138
139 __commandBuffer.append(SocketClient.NETASCII_EOL);
140
141 _writer.write(message = __commandBuffer.toString());
142 _writer.flush();
143
144 if (_commandSupport_.getListenerCount() > 0)
145 _commandSupport_.fireCommandSent(command, message);
146
147 __getReply();
148 return _replyCode;
149 }
150
151 private int __sendCommand(int command, String args, boolean includeSpace)
152 throws IOException
153 {
154 return __sendCommand(SMTPCommand._commands[command], args, includeSpace);
155 }
156
157 private void __getReply() throws IOException
158 {
159 int length;
160
161 _newReplyString = true;
162 _replyLines.setSize(0);
163
164 String line = _reader.readLine();
165
166 if (line == null)
167 throw new SMTPConnectionClosedException(
168 "Connection closed without indication.");
169
170
171
172 length = line.length();
173 if (length < 3)
174 throw new MalformedServerReplyException(
175 "Truncated server reply: " + line);
176
177 try
178 {
179 String code = line.substring(0, 3);
180 _replyCode = Integer.parseInt(code);
181 }
182 catch (NumberFormatException e)
183 {
184 throw new MalformedServerReplyException(
185 "Could not parse response code.\nServer Reply: " + line);
186 }
187
188 _replyLines.addElement(line);
189
190
191 if (length > 3 && line.charAt(3) == '-')
192 {
193 do
194 {
195 line = _reader.readLine();
196
197 if (line == null)
198 throw new SMTPConnectionClosedException(
199 "Connection closed without indication.");
200
201 _replyLines.addElement(line);
202
203
204
205
206 }
207 while (!(line.length() >= 4 && line.charAt(3) != '-' &&
208 Character.isDigit(line.charAt(0))));
209
210
211
212 }
213
214 if (_commandSupport_.getListenerCount() > 0)
215 _commandSupport_.fireReplyReceived(_replyCode, getReplyString());
216
217 if (_replyCode == SMTPReply.SERVICE_NOT_AVAILABLE)
218 throw new SMTPConnectionClosedException(
219 "SMTP response 421 received. Server closed connection.");
220 }
221
222 /*** Initiates control connections and gets initial reply. ***/
223 protected void _connectAction_() throws IOException
224 {
225 super._connectAction_();
226 _reader =
227 new BufferedReader(new InputStreamReader(_input_,
228 __DEFAULT_ENCODING));
229 _writer =
230 new BufferedWriter(new OutputStreamWriter(_output_,
231 __DEFAULT_ENCODING));
232 __getReply();
233 }
234
235
236 /***
237 * Adds a ProtocolCommandListener. Delegates this task to
238 * {@link #_commandSupport_ _commandSupport_ }.
239 * <p>
240 * @param listener The ProtocolCommandListener to add.
241 ***/
242 public void addProtocolCommandListener(ProtocolCommandListener listener)
243 {
244 _commandSupport_.addProtocolCommandListener(listener);
245 }
246
247 /***
248 * Removes a ProtocolCommandListener. Delegates this task to
249 * {@link #_commandSupport_ _commandSupport_ }.
250 * <p>
251 * @param listener The ProtocolCommandListener to remove.
252 ***/
253 public void removeProtocolCommandistener(ProtocolCommandListener listener)
254 {
255 _commandSupport_.removeProtocolCommandListener(listener);
256 }
257
258
259 /***
260 * Closes the connection to the SMTP server and sets to null
261 * some internal data so that the memory may be reclaimed by the
262 * garbage collector. The reply text and code information from the
263 * last command is voided so that the memory it used may be reclaimed.
264 * <p>
265 * @exception IOException If an error occurs while disconnecting.
266 ***/
267 public void disconnect() throws IOException
268 {
269 super.disconnect();
270 _reader = null;
271 _writer = null;
272 _replyString = null;
273 _replyLines.setSize(0);
274 _newReplyString = false;
275 }
276
277
278 /***
279 * Sends an SMTP command to the server, waits for a reply and returns the
280 * numerical response code. After invocation, for more detailed
281 * information, the actual reply text can be accessed by calling
282 * {@link #getReplyString getReplyString } or
283 * {@link #getReplyStrings getReplyStrings }.
284 * <p>
285 * @param command The text representation of the SMTP command to send.
286 * @param args The arguments to the SMTP command. If this parameter is
287 * set to null, then the command is sent with no argument.
288 * @return The integer value of the SMTP reply code returned by the server
289 * in response to the command.
290 * @exception SMTPConnectionClosedException
291 * If the SMTP server prematurely closes the connection as a result
292 * of the client being idle or some other reason causing the server
293 * to send SMTP reply code 421. This exception may be caught either
294 * as an IOException or independently as itself.
295 * @exception IOException If an I/O error occurs while either sending the
296 * command or receiving the server reply.
297 ***/
298 public int sendCommand(String command, String args) throws IOException
299 {
300 return __sendCommand(command, args, true);
301 }
302
303
304 /***
305 * Sends an SMTP command to the server, waits for a reply and returns the
306 * numerical response code. After invocation, for more detailed
307 * information, the actual reply text can be accessed by calling
308 * {@link #getReplyString getReplyString } or
309 * {@link #getReplyStrings getReplyStrings }.
310 * <p>
311 * @param command The SMTPCommand constant corresponding to the SMTP command
312 * to send.
313 * @param args The arguments to the SMTP command. If this parameter is
314 * set to null, then the command is sent with no argument.
315 * @return The integer value of the SMTP reply code returned by the server
316 * in response to the command.
317 * @exception SMTPConnectionClosedException
318 * If the SMTP server prematurely closes the connection as a result
319 * of the client being idle or some other reason causing the server
320 * to send SMTP reply code 421. This exception may be caught either
321 * as an IOException or independently as itself.
322 * @exception IOException If an I/O error occurs while either sending the
323 * command or receiving the server reply.
324 ***/
325 public int sendCommand(int command, String args) throws IOException
326 {
327 return sendCommand(SMTPCommand._commands[command], args);
328 }
329
330
331 /***
332 * Sends an SMTP command with no arguments to the server, waits for a
333 * reply and returns the numerical response code. After invocation, for
334 * more detailed information, the actual reply text can be accessed by
335 * calling {@link #getReplyString getReplyString } or
336 * {@link #getReplyStrings getReplyStrings }.
337 * <p>
338 * @param command The text representation of the SMTP command to send.
339 * @return The integer value of the SMTP reply code returned by the server
340 * in response to the command.
341 * @exception SMTPConnectionClosedException
342 * If the SMTP server prematurely closes the connection as a result
343 * of the client being idle or some other reason causing the server
344 * to send SMTP reply code 421. This exception may be caught either
345 * as an IOException or independently as itself.
346 * @exception IOException If an I/O error occurs while either sending the
347 * command or receiving the server reply.
348 ***/
349 public int sendCommand(String command) throws IOException
350 {
351 return sendCommand(command, null);
352 }
353
354
355 /***
356 * Sends an SMTP command with no arguments to the server, waits for a
357 * reply and returns the numerical response code. After invocation, for
358 * more detailed information, the actual reply text can be accessed by
359 * calling {@link #getReplyString getReplyString } or
360 * {@link #getReplyStrings getReplyStrings }.
361 * <p>
362 * @param command The SMTPCommand constant corresponding to the SMTP command
363 * to send.
364 * @return The integer value of the SMTP reply code returned by the server
365 * in response to the command.
366 * @exception SMTPConnectionClosedException
367 * If the SMTP server prematurely closes the connection as a result
368 * of the client being idle or some other reason causing the server
369 * to send SMTP reply code 421. This exception may be caught either
370 * as an IOException or independently as itself.
371 * @exception IOException If an I/O error occurs while either sending the
372 * command or receiving the server reply.
373 ***/
374 public int sendCommand(int command) throws IOException
375 {
376 return sendCommand(command, null);
377 }
378
379
380 /***
381 * Returns the integer value of the reply code of the last SMTP reply.
382 * You will usually only use this method after you connect to the
383 * SMTP server to check that the connection was successful since
384 * <code> connect </code> is of type void.
385 * <p>
386 * @return The integer value of the reply code of the last SMTP reply.
387 ***/
388 public int getReplyCode()
389 {
390 return _replyCode;
391 }
392
393 /***
394 * Fetches a reply from the SMTP server and returns the integer reply
395 * code. After calling this method, the actual reply text can be accessed
396 * from either calling {@link #getReplyString getReplyString } or
397 * {@link #getReplyStrings getReplyStrings }. Only use this
398 * method if you are implementing your own SMTP client or if you need to
399 * fetch a secondary response from the SMTP server.
400 * <p>
401 * @return The integer value of the reply code of the fetched SMTP reply.
402 * @exception SMTPConnectionClosedException
403 * If the SMTP server prematurely closes the connection as a result
404 * of the client being idle or some other reason causing the server
405 * to send SMTP reply code 421. This exception may be caught either
406 * as an IOException or independently as itself.
407 * @exception IOException If an I/O error occurs while receiving the
408 * server reply.
409 ***/
410 public int getReply() throws IOException
411 {
412 __getReply();
413 return _replyCode;
414 }
415
416
417 /***
418 * Returns the lines of text from the last SMTP server response as an array
419 * of strings, one entry per line. The end of line markers of each are
420 * stripped from each line.
421 * <p>
422 * @return The lines of text from the last SMTP response as an array.
423 ***/
424 public String[] getReplyStrings()
425 {
426 String[] lines;
427 lines = new String[_replyLines.size()];
428 _replyLines.copyInto(lines);
429 return lines;
430 }
431
432 /***
433 * Returns the entire text of the last SMTP server response exactly
434 * as it was received, including all end of line markers in NETASCII
435 * format.
436 * <p>
437 * @return The entire text from the last SMTP response as a String.
438 ***/
439 public String getReplyString()
440 {
441 Enumeration en;
442 StringBuffer buffer;
443
444 if (!_newReplyString)
445 return _replyString;
446
447 buffer = new StringBuffer(256);
448 en = _replyLines.elements();
449 while (en.hasMoreElements())
450 {
451 buffer.append((String)en.nextElement());
452 buffer.append(SocketClient.NETASCII_EOL);
453 }
454
455 _newReplyString = false;
456
457 return (_replyString = buffer.toString());
458 }
459
460
461 /***
462 * A convenience method to send the SMTP HELO command to the server,
463 * receive the reply, and return the reply code.
464 * <p>
465 * @param hostname The hostname of the sender.
466 * @return The reply code received from the server.
467 * @exception SMTPConnectionClosedException
468 * If the SMTP server prematurely closes the connection as a result
469 * of the client being idle or some other reason causing the server
470 * to send SMTP reply code 421. This exception may be caught either
471 * as an IOException or independently as itself.
472 * @exception IOException If an I/O error occurs while either sending the
473 * command or receiving the server reply.
474 ***/
475 public int helo(String hostname) throws IOException
476 {
477 return sendCommand(SMTPCommand.HELO, hostname);
478 }
479
480
481 /***
482 * A convenience method to send the SMTP MAIL command to the server,
483 * receive the reply, and return the reply code.
484 * <p>
485 * @param reversePath The reverese path.
486 * @return The reply code received from the server.
487 * @exception SMTPConnectionClosedException
488 * If the SMTP server prematurely closes the connection as a result
489 * of the client being idle or some other reason causing the server
490 * to send SMTP reply code 421. This exception may be caught either
491 * as an IOException or independently as itself.
492 * @exception IOException If an I/O error occurs while either sending the
493 * command or receiving the server reply.
494 ***/
495 public int mail(String reversePath) throws IOException
496 {
497 return __sendCommand(SMTPCommand.MAIL, reversePath, false);
498 }
499
500
501 /***
502 * A convenience method to send the SMTP RCPT command to the server,
503 * receive the reply, and return the reply code.
504 * <p>
505 * @param forwardPath The forward path.
506 * @return The reply code received from the server.
507 * @exception SMTPConnectionClosedException
508 * If the SMTP server prematurely closes the connection as a result
509 * of the client being idle or some other reason causing the server
510 * to send SMTP reply code 421. This exception may be caught either
511 * as an IOException or independently as itself.
512 * @exception IOException If an I/O error occurs while either sending the
513 * command or receiving the server reply.
514 ***/
515 public int rcpt(String forwardPath) throws IOException
516 {
517 return __sendCommand(SMTPCommand.RCPT, forwardPath, false);
518 }
519
520
521 /***
522 * A convenience method to send the SMTP DATA command to the server,
523 * receive the reply, and return the reply code.
524 * <p>
525 * @return The reply code received from the server.
526 * @exception SMTPConnectionClosedException
527 * If the SMTP server prematurely closes the connection as a result
528 * of the client being idle or some other reason causing the server
529 * to send SMTP reply code 421. This exception may be caught either
530 * as an IOException or independently as itself.
531 * @exception IOException If an I/O error occurs while either sending the
532 * command or receiving the server reply.
533 ***/
534 public int data() throws IOException
535 {
536 return sendCommand(SMTPCommand.DATA);
537 }
538
539
540 /***
541 * A convenience method to send the SMTP SEND command to the server,
542 * receive the reply, and return the reply code.
543 * <p>
544 * @param reversePath The reverese path.
545 * @return The reply code received from the server.
546 * @exception SMTPConnectionClosedException
547 * If the SMTP server prematurely closes the connection as a result
548 * of the client being idle or some other reason causing the server
549 * to send SMTP reply code 421. This exception may be caught either
550 * as an IOException or independently as itself.
551 * @exception IOException If an I/O error occurs while either sending the
552 * command or receiving the server reply.
553 ***/
554 public int send(String reversePath) throws IOException
555 {
556 return sendCommand(SMTPCommand.SEND, reversePath);
557 }
558
559
560 /***
561 * A convenience method to send the SMTP SOML command to the server,
562 * receive the reply, and return the reply code.
563 * <p>
564 * @param reversePath The reverese path.
565 * @return The reply code received from the server.
566 * @exception SMTPConnectionClosedException
567 * If the SMTP server prematurely closes the connection as a result
568 * of the client being idle or some other reason causing the server
569 * to send SMTP reply code 421. This exception may be caught either
570 * as an IOException or independently as itself.
571 * @exception IOException If an I/O error occurs while either sending the
572 * command or receiving the server reply.
573 ***/
574 public int soml(String reversePath) throws IOException
575 {
576 return sendCommand(SMTPCommand.SOML, reversePath);
577 }
578
579
580 /***
581 * A convenience method to send the SMTP SAML command to the server,
582 * receive the reply, and return the reply code.
583 * <p>
584 * @param reversePath The reverese path.
585 * @return The reply code received from the server.
586 * @exception SMTPConnectionClosedException
587 * If the SMTP server prematurely closes the connection as a result
588 * of the client being idle or some other reason causing the server
589 * to send SMTP reply code 421. This exception may be caught either
590 * as an IOException or independently as itself.
591 * @exception IOException If an I/O error occurs while either sending the
592 * command or receiving the server reply.
593 ***/
594 public int saml(String reversePath) throws IOException
595 {
596 return sendCommand(SMTPCommand.SAML, reversePath);
597 }
598
599
600 /***
601 * A convenience method to send the SMTP RSET command to the server,
602 * receive the reply, and return the reply code.
603 * <p>
604 * @return The reply code received from the server.
605 * @exception SMTPConnectionClosedException
606 * If the SMTP server prematurely closes the connection as a result
607 * of the client being idle or some other reason causing the server
608 * to send SMTP reply code 421. This exception may be caught either
609 * as an IOException or independently as itself.
610 * @exception IOException If an I/O error occurs while either sending the
611 * command or receiving the server reply.
612 ***/
613 public int rset() throws IOException
614 {
615 return sendCommand(SMTPCommand.RSET);
616 }
617
618
619 /***
620 * A convenience method to send the SMTP VRFY command to the server,
621 * receive the reply, and return the reply code.
622 * <p>
623 * @param user The user address to verify.
624 * @return The reply code received from the server.
625 * @exception SMTPConnectionClosedException
626 * If the SMTP server prematurely closes the connection as a result
627 * of the client being idle or some other reason causing the server
628 * to send SMTP reply code 421. This exception may be caught either
629 * as an IOException or independently as itself.
630 * @exception IOException If an I/O error occurs while either sending the
631 * command or receiving the server reply.
632 ***/
633 public int vrfy(String user) throws IOException
634 {
635 return sendCommand(SMTPCommand.VRFY, user);
636 }
637
638
639 /***
640 * A convenience method to send the SMTP VRFY command to the server,
641 * receive the reply, and return the reply code.
642 * <p>
643 * @param name The name to expand.
644 * @return The reply code received from the server.
645 * @exception SMTPConnectionClosedException
646 * If the SMTP server prematurely closes the connection as a result
647 * of the client being idle or some other reason causing the server
648 * to send SMTP reply code 421. This exception may be caught either
649 * as an IOException or independently as itself.
650 * @exception IOException If an I/O error occurs while either sending the
651 * command or receiving the server reply.
652 ***/
653 public int expn(String name) throws IOException
654 {
655 return sendCommand(SMTPCommand.EXPN, name);
656 }
657
658 /***
659 * A convenience method to send the SMTP HELP command to the server,
660 * receive the reply, and return the reply code.
661 * <p>
662 * @return The reply code received from the server.
663 * @exception SMTPConnectionClosedException
664 * If the SMTP server prematurely closes the connection as a result
665 * of the client being idle or some other reason causing the server
666 * to send SMTP reply code 421. This exception may be caught either
667 * as an IOException or independently as itself.
668 * @exception IOException If an I/O error occurs while either sending the
669 * command or receiving the server reply.
670 ***/
671 public int help() throws IOException
672 {
673 return sendCommand(SMTPCommand.HELP);
674 }
675
676 /***
677 * A convenience method to send the SMTP HELP command to the server,
678 * receive the reply, and return the reply code.
679 * <p>
680 * @param command The command name on which to request help.
681 * @return The reply code received from the server.
682 * @exception SMTPConnectionClosedException
683 * If the SMTP server prematurely closes the connection as a result
684 * of the client being idle or some other reason causing the server
685 * to send SMTP reply code 421. This exception may be caught either
686 * as an IOException or independently as itself.
687 * @exception IOException If an I/O error occurs while either sending the
688 * command or receiving the server reply.
689 ***/
690 public int help(String command) throws IOException
691 {
692 return sendCommand(SMTPCommand.HELP, command);
693 }
694
695 /***
696 * A convenience method to send the SMTP NOOP command to the server,
697 * receive the reply, and return the reply code.
698 * <p>
699 * @return The reply code received from the server.
700 * @exception SMTPConnectionClosedException
701 * If the SMTP server prematurely closes the connection as a result
702 * of the client being idle or some other reason causing the server
703 * to send SMTP reply code 421. This exception may be caught either
704 * as an IOException or independently as itself.
705 * @exception IOException If an I/O error occurs while either sending the
706 * command or receiving the server reply.
707 ***/
708 public int noop() throws IOException
709 {
710 return sendCommand(SMTPCommand.NOOP);
711 }
712
713
714 /***
715 * A convenience method to send the SMTP TURN command to the server,
716 * receive the reply, and return the reply code.
717 * <p>
718 * @return The reply code received from the server.
719 * @exception SMTPConnectionClosedException
720 * If the SMTP server prematurely closes the connection as a result
721 * of the client being idle or some other reason causing the server
722 * to send SMTP reply code 421. This exception may be caught either
723 * as an IOException or independently as itself.
724 * @exception IOException If an I/O error occurs while either sending the
725 * command or receiving the server reply.
726 ***/
727 public int turn() throws IOException
728 {
729 return sendCommand(SMTPCommand.TURN);
730 }
731
732
733 /***
734 * A convenience method to send the SMTP QUIT command to the server,
735 * receive the reply, and return the reply code.
736 * <p>
737 * @return The reply code received from the server.
738 * @exception SMTPConnectionClosedException
739 * If the SMTP server prematurely closes the connection as a result
740 * of the client being idle or some other reason causing the server
741 * to send SMTP reply code 421. This exception may be caught either
742 * as an IOException or independently as itself.
743 * @exception IOException If an I/O error occurs while either sending the
744 * command or receiving the server reply.
745 ***/
746 public int quit() throws IOException
747 {
748 return sendCommand(SMTPCommand.QUIT);
749 }
750
751 }
752
753
754
755
756
757
758
759