1 package org.apache.commons.net.smtp;
2
3 /* ====================================================================
4 * The Apache Software License, Version 1.1
5 *
6 * Copyright (c) 2001 The Apache Software Foundation. All rights
7 * reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
19 * distribution.
20 *
21 * 3. The end-user documentation included with the redistribution,
22 * if any, must include the following acknowledgment:
23 * "This product includes software developed by the
24 * Apache Software Foundation (http://www.apache.org/)."
25 * Alternately, this acknowledgment may appear in the software itself,
26 * if and wherever such third-party acknowledgments normally appear.
27 *
28 * 4. The names "Apache" and "Apache Software Foundation" and
29 * "Apache Commons" must not be used to endorse or promote products
30 * derived from this software without prior written permission. For
31 * written permission, please contact apache@apache.org.
32 *
33 * 5. Products derived from this software may not be called "Apache",
34 * nor may "Apache" appear in their name, without
35 * prior written permission of the Apache Software Foundation.
36 *
37 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
41 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48 * SUCH DAMAGE.
49 * ====================================================================
50 *
51 * This software consists of voluntary contributions made by many
52 * individuals on behalf of the Apache Software Foundation. For more
53 * information on the Apache Software Foundation, please see
54 * <http://www.apache.org/>.
55 */
56
57 import java.io.IOException;
58 import java.io.Writer;
59 import java.net.InetAddress;
60 import org.apache.commons.net.io.DotTerminatedMessageWriter;
61
62 /****
63 * SMTPClient encapsulates all the functionality necessary to send files
64 * through an SMTP server. This class takes care of all
65 * low level details of interacting with an SMTP server and provides
66 * a convenient higher level interface. As with all classes derived
67 * from <a href="org.apache.commons.net.SocketClient.html"> SocketClient </a>,
68 * you must first connect to the server with
69 * <a href="org.apache.commons.net.SocketClient.html#connect"> connect </a>
70 * before doing anything, and finally
71 * <a href="org.apache.commons.net.SocketClient.html#disconnect"> disconnect </a>
72 * after you're completely finished interacting with the server.
73 * Then you need to check the SMTP reply code to see if the connection
74 * was successful. For example:
75 * <pre>
76 * try {
77 * int reply;
78 * client.connect("mail.foobar.com");
79 * System.out.print(client.getReplyString());
80 *
81 * // After connection attempt, you should check the reply code to verify
82 * // success.
83 * reply = client.getReplyCode();
84 *
85 * if(!SMTPReply.isPositiveCompletion(reply)) {
86 * client.disconnect();
87 * System.err.println("SMTP server refused connection.");
88 * System.exit(1);
89 * }
90 *
91 * // Do useful stuff here.
92 * ...
93 * } catch(IOException e) {
94 * if(client.isConnected()) {
95 * try {
96 * client.disconnect();
97 * } catch(IOException f) {
98 * // do nothing
99 * }
100 * }
101 * System.err.println("Could not connect to server.");
102 * e.printStackTrace();
103 * System.exit(1);
104 * }
105 * </pre>
106 * <p>
107 * Immediately after connecting is the only real time you need to check the
108 * reply code (because connect is of type void). The convention for all the
109 * SMTP command methods in SMTPClient is such that they either return a
110 * boolean value or some other value.
111 * The boolean methods return true on a successful completion reply from
112 * the SMTP server and false on a reply resulting in an error condition or
113 * failure. The methods returning a value other than boolean return a value
114 * containing the higher level data produced by the SMTP command, or null if a
115 * reply resulted in an error condition or failure. If you want to access
116 * the exact SMTP reply code causing a success or failure, you must call
117 * <a href="org.apache.commons.net.smtp.SMTP.html#getReplyCode"> getReplyCode </a> after
118 * a success or failure.
119 * <p>
120 * You should keep in mind that the SMTP server may choose to prematurely
121 * close a connection for various reasons. The SMTPClient class will detect a
122 * premature SMTP server connection closing when it receives a
123 * <a href="org.apache.commons.net.smtp.SMTPReply.html#SERVICE_NOT_AVAILABLE">
124 * SMTPReply.SERVICE_NOT_AVAILABLE </a> response to a command.
125 * When that occurs, the method encountering that reply will throw
126 * an <a href="org.apache.commons.net.smtp.SMTPConnectionClosedException.html">
127 * SMTPConnectionClosedException </a>.
128 * <code>SMTPConectionClosedException</code>
129 * is a subclass of <code> IOException </code> and therefore need not be
130 * caught separately, but if you are going to catch it separately, its
131 * catch block must appear before the more general <code> IOException </code>
132 * catch block. When you encounter an
133 * <a href="org.apache.commons.net.smtp.SMTPConnectionClosedException.html">
134 * SMTPConnectionClosedException </a>, you must disconnect the connection with
135 * <a href="#disconnect"> disconnect() </a> to properly clean up the
136 * system resources used by SMTPClient. Before disconnecting, you may check
137 * the last reply code and text with
138 * <a href="org.apache.commons.net.smtp.SMTP.html#getReplyCode"> getReplyCode </a>,
139 * <a href="org.apache.commons.net.smtp.SMTP.html#getReplyString"> getReplyString </a>,
140 * and
141 * <a href="org.apache.commons.net.smtp.SMTP.html#getReplyStrings">getReplyStrings</a>.
142 * <p>
143 * Rather than list it separately for each method, we mention here that
144 * every method communicating with the server and throwing an IOException
145 * can also throw a
146 * <a href="org.apache.commons.net.MalformedServerReplyException.html">
147 * MalformedServerReplyException </a>, which is a subclass
148 * of IOException. A MalformedServerReplyException will be thrown when
149 * the reply received from the server deviates enough from the protocol
150 * specification that it cannot be interpreted in a useful manner despite
151 * attempts to be as lenient as possible.
152 * <p>
153 * <p>
154 * @author Daniel F. Savarese
155 * @see SMTP
156 * @see SimpleSMTPHeader
157 * @see RelayPath
158 * @see SMTPConnectionClosedException
159 * @see org.apache.commons.net.MalformedServerReplyException
160 ***/
161
162 public class SMTPClient extends SMTP
163 {
164
165 /*
166 * Default SMTPClient constructor. Creates a new SMTPClient instance.
167 */
168 //public SMTPClient() { }
169
170
171 /****
172 * At least one SMTPClient method (<a href="#sendMessage"> sendMessage </a>)
173 * does not complete the entire sequence of SMTP commands to complete a
174 * transaction. These types of commands require some action by the
175 * programmer after the reception of a positive intermediate command.
176 * After the programmer's code completes its actions, it must call this
177 * method to receive the completion reply from the server and verify the
178 * success of the entire transaction.
179 * <p>
180 * For example,
181 * <pre>
182 * writer = client.sendMessage();
183 * if(writer == null) // failure
184 * return false;
185 * header =
186 * new SimpleSMTPHeader("foobar@foo.com", "foo@foobar.com", "Re: Foo");
187 * writer.write(header.toString());
188 * writer.write("This is just a test");
189 * writer.close();
190 * if(!client.completePendingCommand()) // failure
191 * return false;
192 * </pre>
193 * <p>
194 * @return True if successfully completed, false if not.
195 * @exception SMTPConnectionClosedException
196 * If the SMTP server prematurely closes the connection as a result
197 * of the client being idle or some other reason causing the server
198 * to send SMTP reply code 421. This exception may be caught either
199 * as an IOException or independently as itself.
200 * @exception IOException If an I/O error occurs while either sending a
201 * command to the server or receiving a reply from the server.
202 ***/
203 public boolean completePendingCommand() throws IOException
204 {
205 return SMTPReply.isPositiveCompletion(getReply());
206 }
207
208
209 /****
210 * Login to the SMTP server by sending the HELO command with the
211 * given hostname as an argument. Before performing any mail commands,
212 * you must first login.
213 * <p>
214 * @param hostname The hostname with which to greet the SMTP server.
215 * @return True if successfully completed, false if not.
216 * @exception SMTPConnectionClosedException
217 * If the SMTP server prematurely closes the connection as a result
218 * of the client being idle or some other reason causing the server
219 * to send SMTP reply code 421. This exception may be caught either
220 * as an IOException or independently as itself.
221 * @exception IOException If an I/O error occurs while either sending a
222 * command to the server or receiving a reply from the server.
223 ***/
224 public boolean login(String hostname) throws IOException
225 {
226 return SMTPReply.isPositiveCompletion(helo(hostname));
227 }
228
229
230 /****
231 * Login to the SMTP server by sending the HELO command with the
232 * client hostname as an argument. Before performing any mail commands,
233 * you must first login.
234 * <p>
235 * @return True if successfully completed, false if not.
236 * @exception SMTPConnectionClosedException
237 * If the SMTP server prematurely closes the connection as a result
238 * of the client being idle or some other reason causing the server
239 * to send SMTP reply code 421. This exception may be caught either
240 * as an IOException or independently as itself.
241 * @exception IOException If an I/O error occurs while either sending a
242 * command to the server or receiving a reply from the server.
243 ***/
244 public boolean login() throws IOException
245 {
246 String name;
247 InetAddress host;
248
249 host = getLocalAddress();
250 name = host.getHostName();
251
252 if (name == null)
253 return false;
254
255 return SMTPReply.isPositiveCompletion(helo(name));
256 }
257
258
259 /****
260 * Set the sender of a message using the SMTP MAIL command, specifying
261 * a reverse relay path. The sender must be set first before any
262 * recipients may be specified, otherwise the mail server will reject
263 * your commands.
264 * <p>
265 * @param path The reverse relay path pointing back to the sender.
266 * @return True if successfully completed, false if not.
267 * @exception SMTPConnectionClosedException
268 * If the SMTP server prematurely closes the connection as a result
269 * of the client being idle or some other reason causing the server
270 * to send SMTP reply code 421. This exception may be caught either
271 * as an IOException or independently as itself.
272 * @exception IOException If an I/O error occurs while either sending a
273 * command to the server or receiving a reply from the server.
274 ***/
275 public boolean setSender(RelayPath path) throws IOException
276 {
277 return SMTPReply.isPositiveCompletion(mail(path.toString()));
278 }
279
280
281 /****
282 * Set the sender of a message using the SMTP MAIL command, specifying
283 * the sender's email address. The sender must be set first before any
284 * recipients may be specified, otherwise the mail server will reject
285 * your commands.
286 * <p>
287 * @param address The sender's email address.
288 * @return True if successfully completed, false if not.
289 * @exception SMTPConnectionClosedException
290 * If the SMTP server prematurely closes the connection as a result
291 * of the client being idle or some other reason causing the server
292 * to send SMTP reply code 421. This exception may be caught either
293 * as an IOException or independently as itself.
294 * @exception IOException If an I/O error occurs while either sending a
295 * command to the server or receiving a reply from the server.
296 ***/
297 public boolean setSender(String address) throws IOException
298 {
299 return SMTPReply.isPositiveCompletion(mail("<" + address + ">"));
300 }
301
302
303 /****
304 * Add a recipient for a message using the SMTP RCPT command, specifying
305 * a forward relay path. The sender must be set first before any
306 * recipients may be specified, otherwise the mail server will reject
307 * your commands.
308 * <p>
309 * @param path The forward relay path pointing to the recipient.
310 * @return True if successfully completed, false if not.
311 * @exception SMTPConnectionClosedException
312 * If the SMTP server prematurely closes the connection as a result
313 * of the client being idle or some other reason causing the server
314 * to send SMTP reply code 421. This exception may be caught either
315 * as an IOException or independently as itself.
316 * @exception IOException If an I/O error occurs while either sending a
317 * command to the server or receiving a reply from the server.
318 ***/
319 public boolean addRecipient(RelayPath path) throws IOException
320 {
321 return SMTPReply.isPositiveCompletion(rcpt(path.toString()));
322 }
323
324
325 /****
326 * Add a recipient for a message using the SMTP RCPT command, the
327 * recipient's email address. The sender must be set first before any
328 * recipients may be specified, otherwise the mail server will reject
329 * your commands.
330 * <p>
331 * @param address The recipient's email address.
332 * @return True if successfully completed, false if not.
333 * @exception SMTPConnectionClosedException
334 * If the SMTP server prematurely closes the connection as a result
335 * of the client being idle or some other reason causing the server
336 * to send SMTP reply code 421. This exception may be caught either
337 * as an IOException or independently as itself.
338 * @exception IOException If an I/O error occurs while either sending a
339 * command to the server or receiving a reply from the server.
340 ***/
341 public boolean addRecipient(String address) throws IOException
342 {
343 return SMTPReply.isPositiveCompletion(rcpt("<" + address + ">"));
344 }
345
346
347
348 /****
349 * Send the SMTP DATA command in preparation to send an email message.
350 * This method returns a DotTerminatedMessageWriter instance to which
351 * the message can be written. Null is returned if the DATA command
352 * fails.
353 * <p>
354 * You must not issue any commands to the SMTP server (i.e., call any
355 * (other methods) until you finish writing to the returned Writer
356 * instance and close it. The SMTP protocol uses the same stream for
357 * issuing commands as it does for returning results. Therefore the
358 * returned Writer actually writes directly to the SMTP connection.
359 * After you close the writer, you can execute new commands. If you
360 * do not follow these requirements your program will not work properly.
361 * <p>
362 * You can use the provided
363 * <a href="org.apache.commons.net.smtp.SimpleSMTPHeader.html"> SimpleSMTPHeader </a>
364 * class to construct a bare minimum header.
365 * To construct more complicated headers you should
366 * refer to RFC 822. When the Java Mail API is finalized, you will be
367 * able to use it to compose fully compliant Internet text messages.
368 * The DotTerminatedMessageWriter takes care of doubling line-leading
369 * dots and ending the message with a single dot upon closing, so all
370 * you have to worry about is writing the header and the message.
371 * <p>
372 * Upon closing the returned Writer, you need to call
373 * <a href="#completePendingCommand"> completePendingCommand() </a>
374 * to finalize the transaction and verify its success or failure from
375 * the server reply.
376 * <p>
377 * @return A DotTerminatedMessageWriter to which the message (including
378 * header) can be written. Returns null if the command fails.
379 * @exception SMTPConnectionClosedException
380 * If the SMTP server prematurely closes the connection as a result
381 * of the client being idle or some other reason causing the server
382 * to send SMTP reply code 421. This exception may be caught either
383 * as an IOException or independently as itself.
384 * @exception IOException If an I/O error occurs while either sending a
385 * command to the server or receiving a reply from the server.
386 ***/
387 public Writer sendMessageData() throws IOException
388 {
389 if (!SMTPReply.isPositiveIntermediate(data()))
390 return null;
391
392 return new DotTerminatedMessageWriter(_writer);
393 }
394
395
396 /****
397 * A convenience method for sending short messages. This method fetches
398 * the Writer returned by <a href="#sendMessageData"> sendMessageData() </a>
399 * and writes the specified String to it. After writing the message,
400 * this method calls <a href="#completePendingCommand">
401 * completePendingCommand() </a> to finalize the transaction and returns
402 * its success or failure.
403 * <p>
404 * @param message The short email message to send.
405 * @return True if successfully completed, false if not.
406 * @exception SMTPConnectionClosedException
407 * If the SMTP server prematurely closes the connection as a result
408 * of the client being idle or some other reason causing the server
409 * to send SMTP reply code 421. This exception may be caught either
410 * as an IOException or independently as itself.
411 * @exception IOException If an I/O error occurs while either sending a
412 * command to the server or receiving a reply from the server.
413 ***/
414 public boolean sendShortMessageData(String message) throws IOException
415 {
416 Writer writer;
417
418 writer = sendMessageData();
419
420 if (writer == null)
421 return false;
422
423 writer.write(message);
424 writer.close();
425
426 return completePendingCommand();
427 }
428
429
430 /****
431 * A convenience method for a sending short email without having to
432 * explicitly set the sender and recipient(s). This method
433 * sets the sender and recipient using
434 * <a href="#setSender"> setSender </a> and
435 * <a href="#addRecipient"> addRecipient </a>, and then sends the
436 * message using <a href="#sendShortMessageData"> sendShortMessageData </a>.
437 * <p>
438 * @param sender The email address of the sender.
439 * @param recipient The email address of the recipient.
440 * @param message The short email message to send.
441 * @return True if successfully completed, false if not.
442 * @exception SMTPConnectionClosedException
443 * If the SMTP server prematurely closes the connection as a result
444 * of the client being idle or some other reason causing the server
445 * to send SMTP reply code 421. This exception may be caught either
446 * as an IOException or independently as itself.
447 * @exception IOException If an I/O error occurs while either sending a
448 * command to the server or receiving a reply from the server.
449 ***/
450 public boolean sendSimpleMessage(String sender, String recipient,
451 String message)
452 throws IOException
453 {
454 if (!setSender(sender))
455 return false;
456
457 if (!addRecipient(recipient))
458 return false;
459
460 return sendShortMessageData(message);
461 }
462
463
464
465 /****
466 * A convenience method for a sending short email without having to
467 * explicitly set the sender and recipient(s). This method
468 * sets the sender and recipients using
469 * <a href="#setSender"> setSender </a> and
470 * <a href="#addRecipient"> addRecipient </a>, and then sends the
471 * message using <a href="#sendShortMessageData"> sendShortMessageData </a>.
472 * <p>
473 * @param sender The email address of the sender.
474 * @param recipients An array of recipient email addresses.
475 * @param message The short email message to send.
476 * @return True if successfully completed, false if not.
477 * @exception SMTPConnectionClosedException
478 * If the SMTP server prematurely closes the connection as a result
479 * of the client being idle or some other reason causing the server
480 * to send SMTP reply code 421. This exception may be caught either
481 * as an IOException or independently as itself.
482 * @exception IOException If an I/O error occurs while either sending a
483 * command to the server or receiving a reply from the server.
484 ***/
485 public boolean sendSimpleMessage(String sender, String[] recipients,
486 String message)
487 throws IOException
488 {
489 boolean oneSuccess = false;
490 int count;
491
492 if (!setSender(sender))
493 return false;
494
495 for (count = 0; count < recipients.length; count++)
496 {
497 if (addRecipient(recipients[count]))
498 oneSuccess = true;
499 }
500
501 if (!oneSuccess)
502 return false;
503
504 return sendShortMessageData(message);
505 }
506
507
508 /****
509 * Logout of the SMTP server by sending the QUIT command.
510 * <p>
511 * @return True if successfully completed, false if not.
512 * @exception SMTPConnectionClosedException
513 * If the SMTP server prematurely closes the connection as a result
514 * of the client being idle or some other reason causing the server
515 * to send SMTP reply code 421. This exception may be caught either
516 * as an IOException or independently as itself.
517 * @exception IOException If an I/O error occurs while either sending a
518 * command to the server or receiving a reply from the server.
519 ***/
520 public boolean logout() throws IOException
521 {
522 return SMTPReply.isPositiveCompletion(quit());
523 }
524
525
526
527 /****
528 * Aborts the current mail transaction, resetting all server stored
529 * sender, recipient, and mail data, cleaing all buffers and tables.
530 * <p>
531 * @return True if successfully completed, false if not.
532 * @exception SMTPConnectionClosedException
533 * If the SMTP server prematurely closes the connection as a result
534 * of the client being idle or some other reason causing the server
535 * to send SMTP reply code 421. This exception may be caught either
536 * as an IOException or independently as itself.
537 * @exception IOException If an I/O error occurs while either sending a
538 * command to the server or receiving a reply from the server.
539 ***/
540 public boolean reset() throws IOException
541 {
542 return SMTPReply.isPositiveCompletion(rset());
543 }
544
545
546 /****
547 * Verify that a username or email address is valid, i.e., that mail
548 * can be delivered to that mailbox on the server.
549 * <p>
550 * @param username The username or email address to validate.
551 * @return True if the username is valid, false if not.
552 * @exception SMTPConnectionClosedException
553 * If the SMTP server prematurely closes the connection as a result
554 * of the client being idle or some other reason causing the server
555 * to send SMTP reply code 421. This exception may be caught either
556 * as an IOException or independently as itself.
557 * @exception IOException If an I/O error occurs while either sending a
558 * command to the server or receiving a reply from the server.
559 ***/
560 public boolean verify(String username) throws IOException
561 {
562 int result;
563
564 result = vrfy(username);
565
566 return (result == SMTPReply.ACTION_OK ||
567 result == SMTPReply.USER_NOT_LOCAL_WILL_FORWARD);
568 }
569
570
571 /****
572 * Fetches the system help information from the server and returns the
573 * full string.
574 * <p>
575 * @return The system help string obtained from the server. null if the
576 * information could not be obtained.
577 * @exception SMTPConnectionClosedException
578 * If the SMTP server prematurely closes the connection as a result
579 * of the client being idle or some other reason causing the server
580 * to send SMTP reply code 421. This exception may be caught either
581 * as an IOException or independently as itself.
582 * @exception IOException If an I/O error occurs while either sending a
583 * command to the server or receiving a reply from the server.
584 ***/
585 public String listHelp() throws IOException
586 {
587 if (SMTPReply.isPositiveCompletion(help()))
588 return getReplyString();
589 return null;
590 }
591
592
593 /****
594 * Fetches the help information for a given command from the server and
595 * returns the full string.
596 * <p>
597 * @param The command on which to ask for help.
598 * @return The command help string obtained from the server. null if the
599 * information could not be obtained.
600 * @exception SMTPConnectionClosedException
601 * If the SMTP server prematurely closes the connection as a result
602 * of the client being idle or some other reason causing the server
603 * to send SMTP reply code 421. This exception may be caught either
604 * as an IOException or independently as itself.
605 * @exception IOException If an I/O error occurs while either sending a
606 * command to the server or receiving a reply from the server.
607 ***/
608 public String listHelp(String command) throws IOException
609 {
610 if (SMTPReply.isPositiveCompletion(help(command)))
611 return getReplyString();
612 return null;
613 }
614
615
616 /****
617 * Sends a NOOP command to the SMTP server. This is useful for preventing
618 * server timeouts.
619 * <p>
620 * @return True if successfully completed, false if not.
621 * @exception SMTPConnectionClosedException
622 * If the SMTP server prematurely closes the connection as a result
623 * of the client being idle or some other reason causing the server
624 * to send SMTP reply code 421. This exception may be caught either
625 * as an IOException or independently as itself.
626 * @exception IOException If an I/O error occurs while either sending a
627 * command to the server or receiving a reply from the server.
628 ***/
629 public boolean sendNoOp() throws IOException
630 {
631 return SMTPReply.isPositiveCompletion(noop());
632 }
633
634 }
This page was automatically generated by Maven