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 }