001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 package org.apache.commons.net.smtp;
019
020 import java.io.IOException;
021 import java.io.Writer;
022 import java.net.InetAddress;
023
024 import org.apache.commons.net.io.DotTerminatedMessageWriter;
025
026 /***
027 * SMTPClient encapsulates all the functionality necessary to send files
028 * through an SMTP server. This class takes care of all
029 * low level details of interacting with an SMTP server and provides
030 * a convenient higher level interface. As with all classes derived
031 * from {@link org.apache.commons.net.SocketClient},
032 * you must first connect to the server with
033 * {@link org.apache.commons.net.SocketClient#connect connect }
034 * before doing anything, and finally
035 * {@link org.apache.commons.net.SocketClient#disconnect disconnect }
036 * after you're completely finished interacting with the server.
037 * Then you need to check the SMTP reply code to see if the connection
038 * was successful. For example:
039 * <pre>
040 * try {
041 * int reply;
042 * client.connect("mail.foobar.com");
043 * System.out.print(client.getReplyString());
044 *
045 * // After connection attempt, you should check the reply code to verify
046 * // success.
047 * reply = client.getReplyCode();
048 *
049 * if(!SMTPReply.isPositiveCompletion(reply)) {
050 * client.disconnect();
051 * System.err.println("SMTP server refused connection.");
052 * System.exit(1);
053 * }
054 *
055 * // Do useful stuff here.
056 * ...
057 * } catch(IOException e) {
058 * if(client.isConnected()) {
059 * try {
060 * client.disconnect();
061 * } catch(IOException f) {
062 * // do nothing
063 * }
064 * }
065 * System.err.println("Could not connect to server.");
066 * e.printStackTrace();
067 * System.exit(1);
068 * }
069 * </pre>
070 * <p>
071 * Immediately after connecting is the only real time you need to check the
072 * reply code (because connect is of type void). The convention for all the
073 * SMTP command methods in SMTPClient is such that they either return a
074 * boolean value or some other value.
075 * The boolean methods return true on a successful completion reply from
076 * the SMTP server and false on a reply resulting in an error condition or
077 * failure. The methods returning a value other than boolean return a value
078 * containing the higher level data produced by the SMTP command, or null if a
079 * reply resulted in an error condition or failure. If you want to access
080 * the exact SMTP reply code causing a success or failure, you must call
081 * {@link org.apache.commons.net.smtp.SMTP#getReplyCode getReplyCode } after
082 * a success or failure.
083 * <p>
084 * You should keep in mind that the SMTP server may choose to prematurely
085 * close a connection for various reasons. The SMTPClient class will detect a
086 * premature SMTP server connection closing when it receives a
087 * {@link org.apache.commons.net.smtp.SMTPReply#SERVICE_NOT_AVAILABLE SMTPReply.SERVICE_NOT_AVAILABLE }
088 * response to a command.
089 * When that occurs, the method encountering that reply will throw
090 * an {@link org.apache.commons.net.smtp.SMTPConnectionClosedException}
091 * .
092 * <code>SMTPConectionClosedException</code>
093 * is a subclass of <code> IOException </code> and therefore need not be
094 * caught separately, but if you are going to catch it separately, its
095 * catch block must appear before the more general <code> IOException </code>
096 * catch block. When you encounter an
097 * {@link org.apache.commons.net.smtp.SMTPConnectionClosedException}
098 * , you must disconnect the connection with
099 * {@link #disconnect disconnect() } to properly clean up the
100 * system resources used by SMTPClient. Before disconnecting, you may check
101 * the last reply code and text with
102 * {@link org.apache.commons.net.smtp.SMTP#getReplyCode getReplyCode },
103 * {@link org.apache.commons.net.smtp.SMTP#getReplyString getReplyString },
104 * and
105 * {@link org.apache.commons.net.smtp.SMTP#getReplyStrings getReplyStrings}.
106 * <p>
107 * Rather than list it separately for each method, we mention here that
108 * every method communicating with the server and throwing an IOException
109 * can also throw a
110 * {@link org.apache.commons.net.MalformedServerReplyException}
111 * , which is a subclass
112 * of IOException. A MalformedServerReplyException will be thrown when
113 * the reply received from the server deviates enough from the protocol
114 * specification that it cannot be interpreted in a useful manner despite
115 * attempts to be as lenient as possible.
116 * <p>
117 * <p>
118 * @author Daniel F. Savarese
119 * @see SMTP
120 * @see SimpleSMTPHeader
121 * @see RelayPath
122 * @see SMTPConnectionClosedException
123 * @see org.apache.commons.net.MalformedServerReplyException
124 ***/
125
126 public class SMTPClient extends SMTP
127 {
128
129 /**
130 * Default SMTPClient constructor. Creates a new SMTPClient instance.
131 */
132 public SMTPClient() { }
133
134 /**
135 * Overloaded constructor that takes an encoding specification
136 * @param encoding The encoding to use
137 * @since 2.0
138 */
139 public SMTPClient(String encoding) {
140 super(encoding);
141 }
142
143
144 /***
145 * At least one SMTPClient method ({@link #sendMessageData sendMessageData })
146 * does not complete the entire sequence of SMTP commands to complete a
147 * transaction. These types of commands require some action by the
148 * programmer after the reception of a positive intermediate command.
149 * After the programmer's code completes its actions, it must call this
150 * method to receive the completion reply from the server and verify the
151 * success of the entire transaction.
152 * <p>
153 * For example,
154 * <pre>
155 * writer = client.sendMessage();
156 * if(writer == null) // failure
157 * return false;
158 * header =
159 * new SimpleSMTPHeader("foobar@foo.com", "foo@foobar.com", "Re: Foo");
160 * writer.write(header.toString());
161 * writer.write("This is just a test");
162 * writer.close();
163 * if(!client.completePendingCommand()) // failure
164 * return false;
165 * </pre>
166 * <p>
167 * @return True if successfully completed, false if not.
168 * @exception SMTPConnectionClosedException
169 * If the SMTP server prematurely closes the connection as a result
170 * of the client being idle or some other reason causing the server
171 * to send SMTP reply code 421. This exception may be caught either
172 * as an IOException or independently as itself.
173 * @exception IOException If an I/O error occurs while either sending a
174 * command to the server or receiving a reply from the server.
175 ***/
176 public boolean completePendingCommand() throws IOException
177 {
178 return SMTPReply.isPositiveCompletion(getReply());
179 }
180
181
182 /***
183 * Login to the SMTP server by sending the HELO command with the
184 * given hostname as an argument. Before performing any mail commands,
185 * you must first login.
186 * <p>
187 * @param hostname The hostname with which to greet the SMTP server.
188 * @return True if successfully completed, false if not.
189 * @exception SMTPConnectionClosedException
190 * If the SMTP server prematurely closes the connection as a result
191 * of the client being idle or some other reason causing the server
192 * to send SMTP reply code 421. This exception may be caught either
193 * as an IOException or independently as itself.
194 * @exception IOException If an I/O error occurs while either sending a
195 * command to the server or receiving a reply from the server.
196 ***/
197 public boolean login(String hostname) throws IOException
198 {
199 return SMTPReply.isPositiveCompletion(helo(hostname));
200 }
201
202
203 /***
204 * Login to the SMTP server by sending the HELO command with the
205 * client hostname as an argument. Before performing any mail commands,
206 * you must first login.
207 * <p>
208 * @return True if successfully completed, false if not.
209 * @exception SMTPConnectionClosedException
210 * If the SMTP server prematurely closes the connection as a result
211 * of the client being idle or some other reason causing the server
212 * to send SMTP reply code 421. This exception may be caught either
213 * as an IOException or independently as itself.
214 * @exception IOException If an I/O error occurs while either sending a
215 * command to the server or receiving a reply from the server.
216 ***/
217 public boolean login() throws IOException
218 {
219 String name;
220 InetAddress host;
221
222 host = getLocalAddress();
223 name = host.getHostName();
224
225 if (name == null)
226 return false;
227
228 return SMTPReply.isPositiveCompletion(helo(name));
229 }
230
231
232 /***
233 * Set the sender of a message using the SMTP MAIL command, specifying
234 * a reverse relay path. The sender must be set first before any
235 * recipients may be specified, otherwise the mail server will reject
236 * your commands.
237 * <p>
238 * @param path The reverse relay path pointing back to the sender.
239 * @return True if successfully completed, false if not.
240 * @exception SMTPConnectionClosedException
241 * If the SMTP server prematurely closes the connection as a result
242 * of the client being idle or some other reason causing the server
243 * to send SMTP reply code 421. This exception may be caught either
244 * as an IOException or independently as itself.
245 * @exception IOException If an I/O error occurs while either sending a
246 * command to the server or receiving a reply from the server.
247 ***/
248 public boolean setSender(RelayPath path) throws IOException
249 {
250 return SMTPReply.isPositiveCompletion(mail(path.toString()));
251 }
252
253
254 /***
255 * Set the sender of a message using the SMTP MAIL command, specifying
256 * the sender's email address. The sender must be set first before any
257 * recipients may be specified, otherwise the mail server will reject
258 * your commands.
259 * <p>
260 * @param address The sender's email address.
261 * @return True if successfully completed, false if not.
262 * @exception SMTPConnectionClosedException
263 * If the SMTP server prematurely closes the connection as a result
264 * of the client being idle or some other reason causing the server
265 * to send SMTP reply code 421. This exception may be caught either
266 * as an IOException or independently as itself.
267 * @exception IOException If an I/O error occurs while either sending a
268 * command to the server or receiving a reply from the server.
269 ***/
270 public boolean setSender(String address) throws IOException
271 {
272 return SMTPReply.isPositiveCompletion(mail("<" + address + ">"));
273 }
274
275
276 /***
277 * Add a recipient for a message using the SMTP RCPT command, specifying
278 * a forward relay path. The sender must be set first before any
279 * recipients may be specified, otherwise the mail server will reject
280 * your commands.
281 * <p>
282 * @param path The forward relay path pointing to the recipient.
283 * @return True if successfully completed, false if not.
284 * @exception SMTPConnectionClosedException
285 * If the SMTP server prematurely closes the connection as a result
286 * of the client being idle or some other reason causing the server
287 * to send SMTP reply code 421. This exception may be caught either
288 * as an IOException or independently as itself.
289 * @exception IOException If an I/O error occurs while either sending a
290 * command to the server or receiving a reply from the server.
291 ***/
292 public boolean addRecipient(RelayPath path) throws IOException
293 {
294 return SMTPReply.isPositiveCompletion(rcpt(path.toString()));
295 }
296
297
298 /***
299 * Add a recipient for a message using the SMTP RCPT command, the
300 * recipient's email address. The sender must be set first before any
301 * recipients may be specified, otherwise the mail server will reject
302 * your commands.
303 * <p>
304 * @param address The recipient's email address.
305 * @return True if successfully completed, false if not.
306 * @exception SMTPConnectionClosedException
307 * If the SMTP server prematurely closes the connection as a result
308 * of the client being idle or some other reason causing the server
309 * to send SMTP reply code 421. This exception may be caught either
310 * as an IOException or independently as itself.
311 * @exception IOException If an I/O error occurs while either sending a
312 * command to the server or receiving a reply from the server.
313 ***/
314 public boolean addRecipient(String address) throws IOException
315 {
316 return SMTPReply.isPositiveCompletion(rcpt("<" + address + ">"));
317 }
318
319
320
321 /***
322 * Send the SMTP DATA command in preparation to send an email message.
323 * This method returns a DotTerminatedMessageWriter instance to which
324 * the message can be written. Null is returned if the DATA command
325 * fails.
326 * <p>
327 * You must not issue any commands to the SMTP server (i.e., call any
328 * (other methods) until you finish writing to the returned Writer
329 * instance and close it. The SMTP protocol uses the same stream for
330 * issuing commands as it does for returning results. Therefore the
331 * returned Writer actually writes directly to the SMTP connection.
332 * After you close the writer, you can execute new commands. If you
333 * do not follow these requirements your program will not work properly.
334 * <p>
335 * You can use the provided
336 * {@link org.apache.commons.net.smtp.SimpleSMTPHeader}
337 * class to construct a bare minimum header.
338 * To construct more complicated headers you should
339 * refer to RFC 822. When the Java Mail API is finalized, you will be
340 * able to use it to compose fully compliant Internet text messages.
341 * The DotTerminatedMessageWriter takes care of doubling line-leading
342 * dots and ending the message with a single dot upon closing, so all
343 * you have to worry about is writing the header and the message.
344 * <p>
345 * Upon closing the returned Writer, you need to call
346 * {@link #completePendingCommand completePendingCommand() }
347 * to finalize the transaction and verify its success or failure from
348 * the server reply.
349 * <p>
350 * @return A DotTerminatedMessageWriter to which the message (including
351 * header) can be written. Returns null if the command fails.
352 * @exception SMTPConnectionClosedException
353 * If the SMTP server prematurely closes the connection as a result
354 * of the client being idle or some other reason causing the server
355 * to send SMTP reply code 421. This exception may be caught either
356 * as an IOException or independently as itself.
357 * @exception IOException If an I/O error occurs while either sending a
358 * command to the server or receiving a reply from the server.
359 ***/
360 public Writer sendMessageData() throws IOException
361 {
362 if (!SMTPReply.isPositiveIntermediate(data()))
363 return null;
364
365 return new DotTerminatedMessageWriter(_writer);
366 }
367
368
369 /***
370 * A convenience method for sending short messages. This method fetches
371 * the Writer returned by {@link #sendMessageData sendMessageData() }
372 * and writes the specified String to it. After writing the message,
373 * this method calls {@link #completePendingCommand completePendingCommand() }
374 * to finalize the transaction and returns
375 * its success or failure.
376 * <p>
377 * @param message The short email message to send.
378 * @return True if successfully completed, false if not.
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 boolean sendShortMessageData(String message) throws IOException
388 {
389 Writer writer;
390
391 writer = sendMessageData();
392
393 if (writer == null)
394 return false;
395
396 writer.write(message);
397 writer.close();
398
399 return completePendingCommand();
400 }
401
402
403 /***
404 * A convenience method for a sending short email without having to
405 * explicitly set the sender and recipient(s). This method
406 * sets the sender and recipient using
407 * {@link #setSender setSender } and
408 * {@link #addRecipient addRecipient }, and then sends the
409 * message using {@link #sendShortMessageData sendShortMessageData }.
410 * <p>
411 * @param sender The email address of the sender.
412 * @param recipient The email address of the recipient.
413 * @param message The short email message to send.
414 * @return True if successfully completed, false if not.
415 * @exception SMTPConnectionClosedException
416 * If the SMTP server prematurely closes the connection as a result
417 * of the client being idle or some other reason causing the server
418 * to send SMTP reply code 421. This exception may be caught either
419 * as an IOException or independently as itself.
420 * @exception IOException If an I/O error occurs while either sending a
421 * command to the server or receiving a reply from the server.
422 ***/
423 public boolean sendSimpleMessage(String sender, String recipient,
424 String message)
425 throws IOException
426 {
427 if (!setSender(sender))
428 return false;
429
430 if (!addRecipient(recipient))
431 return false;
432
433 return sendShortMessageData(message);
434 }
435
436
437
438 /***
439 * A convenience method for a sending short email without having to
440 * explicitly set the sender and recipient(s). This method
441 * sets the sender and recipients using
442 * {@link #setSender setSender } and
443 * {@link #addRecipient addRecipient }, and then sends the
444 * message using {@link #sendShortMessageData sendShortMessageData }.
445 * <p>
446 * @param sender The email address of the sender.
447 * @param recipients An array of recipient email addresses.
448 * @param message The short email message to send.
449 * @return True if successfully completed, false if not.
450 * @exception SMTPConnectionClosedException
451 * If the SMTP server prematurely closes the connection as a result
452 * of the client being idle or some other reason causing the server
453 * to send SMTP reply code 421. This exception may be caught either
454 * as an IOException or independently as itself.
455 * @exception IOException If an I/O error occurs while either sending a
456 * command to the server or receiving a reply from the server.
457 ***/
458 public boolean sendSimpleMessage(String sender, String[] recipients,
459 String message)
460 throws IOException
461 {
462 boolean oneSuccess = false;
463 int count;
464
465 if (!setSender(sender))
466 return false;
467
468 for (count = 0; count < recipients.length; count++)
469 {
470 if (addRecipient(recipients[count]))
471 oneSuccess = true;
472 }
473
474 if (!oneSuccess)
475 return false;
476
477 return sendShortMessageData(message);
478 }
479
480
481 /***
482 * Logout of the SMTP server by sending the QUIT command.
483 * <p>
484 * @return True if successfully completed, false if not.
485 * @exception SMTPConnectionClosedException
486 * If the SMTP server prematurely closes the connection as a result
487 * of the client being idle or some other reason causing the server
488 * to send SMTP reply code 421. This exception may be caught either
489 * as an IOException or independently as itself.
490 * @exception IOException If an I/O error occurs while either sending a
491 * command to the server or receiving a reply from the server.
492 ***/
493 public boolean logout() throws IOException
494 {
495 return SMTPReply.isPositiveCompletion(quit());
496 }
497
498
499
500 /***
501 * Aborts the current mail transaction, resetting all server stored
502 * sender, recipient, and mail data, cleaing all buffers and tables.
503 * <p>
504 * @return True if successfully completed, false if not.
505 * @exception SMTPConnectionClosedException
506 * If the SMTP server prematurely closes the connection as a result
507 * of the client being idle or some other reason causing the server
508 * to send SMTP reply code 421. This exception may be caught either
509 * as an IOException or independently as itself.
510 * @exception IOException If an I/O error occurs while either sending a
511 * command to the server or receiving a reply from the server.
512 ***/
513 public boolean reset() throws IOException
514 {
515 return SMTPReply.isPositiveCompletion(rset());
516 }
517
518
519 /***
520 * Verify that a username or email address is valid, i.e., that mail
521 * can be delivered to that mailbox on the server.
522 * <p>
523 * @param username The username or email address to validate.
524 * @return True if the username is valid, false if not.
525 * @exception SMTPConnectionClosedException
526 * If the SMTP server prematurely closes the connection as a result
527 * of the client being idle or some other reason causing the server
528 * to send SMTP reply code 421. This exception may be caught either
529 * as an IOException or independently as itself.
530 * @exception IOException If an I/O error occurs while either sending a
531 * command to the server or receiving a reply from the server.
532 ***/
533 public boolean verify(String username) throws IOException
534 {
535 int result;
536
537 result = vrfy(username);
538
539 return (result == SMTPReply.ACTION_OK ||
540 result == SMTPReply.USER_NOT_LOCAL_WILL_FORWARD);
541 }
542
543
544 /***
545 * Fetches the system help information from the server and returns the
546 * full string.
547 * <p>
548 * @return The system help string obtained from the server. null if the
549 * information could not be obtained.
550 * @exception SMTPConnectionClosedException
551 * If the SMTP server prematurely closes the connection as a result
552 * of the client being idle or some other reason causing the server
553 * to send SMTP reply code 421. This exception may be caught either
554 * as an IOException or independently as itself.
555 * @exception IOException If an I/O error occurs while either sending a
556 * command to the server or receiving a reply from the server.
557 ***/
558 public String listHelp() throws IOException
559 {
560 if (SMTPReply.isPositiveCompletion(help()))
561 return getReplyString();
562 return null;
563 }
564
565
566 /***
567 * Fetches the help information for a given command from the server and
568 * returns the full string.
569 * <p>
570 * @param command The command on which to ask for help.
571 * @return The command help string obtained from the server. null if the
572 * information could not be obtained.
573 * @exception SMTPConnectionClosedException
574 * If the SMTP server prematurely closes the connection as a result
575 * of the client being idle or some other reason causing the server
576 * to send SMTP reply code 421. This exception may be caught either
577 * as an IOException or independently as itself.
578 * @exception IOException If an I/O error occurs while either sending a
579 * command to the server or receiving a reply from the server.
580 ***/
581 public String listHelp(String command) throws IOException
582 {
583 if (SMTPReply.isPositiveCompletion(help(command)))
584 return getReplyString();
585 return null;
586 }
587
588
589 /***
590 * Sends a NOOP command to the SMTP server. This is useful for preventing
591 * server timeouts.
592 * <p>
593 * @return True if successfully completed, false if not.
594 * @exception SMTPConnectionClosedException
595 * If the SMTP server prematurely closes the connection as a result
596 * of the client being idle or some other reason causing the server
597 * to send SMTP reply code 421. This exception may be caught either
598 * as an IOException or independently as itself.
599 * @exception IOException If an I/O error occurs while either sending a
600 * command to the server or receiving a reply from the server.
601 ***/
602 public boolean sendNoOp() throws IOException
603 {
604 return SMTPReply.isPositiveCompletion(noop());
605 }
606
607 }