Of course! Let's dive deep into the sendcmd method in Python's built-in ftplib library.

What is ftplib.sendcmd?
The sendcmd method is a low-level function in Python's ftplib module. Its name is short for "send command".
Its primary purpose is to:
- Take a single FTP command string (e.g.,
"USER myusername","PASV","LIST"). - Send it to the FTP server.
- Wait for and return the server's exact response code and message.
This is a fundamental building block for more high-level operations. For example, methods like dir(), cwd(), or retrlines() all use sendcmd internally to perform their tasks.
The Method Signature
sendcmd(cmd)
cmd: A string representing the FTP command. It should be a valid FTP command, often followed by an argument. For example:"USER myusername","CWD /public","PASV".
Return Value
The method returns a string containing the server's response. This string always starts with a three-digit status code, followed by a space, and then the message text.

- Successful 2xx codes: e.g.,
"200 Command okay.","250 Requested file action okay, completed." - Intermediate 1xx codes: e.g.,
"150 File status okay; about to open data connection." - Transient Error 4xx codes: e.g.,
"425 Can't open data connection." - Permanent Error 5xx codes: e.g.,
"550 No such file or directory."
How to Use sendcmd (Practical Examples)
Let's walk through a complete example. We'll connect to a public FTP server and use sendcmd to execute various commands.
Setup: Using a Public FTP Server
For these examples, we'll use the ftp.gnu.org server, which allows anonymous access.
import ftplib
import socket
# --- 1. Basic Connection ---
try:
# Connect to the server
ftp = ftplib.FTP('ftp.gnu.org')
print(f"Successfully connected to {ftp.host}")
print(f"Welcome message: {ftp.getwelcome()}")
# --- 2. Using sendcmd for a simple command ---
# Let's see the current system type (SYST command)
response = ftp.sendcmd('SYST')
print(f"\n--- Command: SYST ---")
print(f"Raw Response: {response}")
# The response is "215 UNIX Type: L8" (or similar)
# The code is 215, the message is "UNIX Type: L8"
print(f"Response Code: {response[:3]}")
print(f"Response Message: {response[4:]}")
# --- 3. Using sendcmd for a command with arguments ---
# Let's change directory to the 'pub' folder
response = ftp.sendcmd('CWD /pub')
print(f"\n--- Command: CWD /pub ---")
print(f"Raw Response: {response}")
# A successful CWD returns "250 Requested file action okay, completed."
# --- 4. Handling an error with sendcmd ---
# Let's try to list a directory that doesn't exist
print("\n--- Command: LIST /nonexistent_directory ---")
try:
response = ftp.sendcmd('LIST /nonexistent_directory')
print(f"Unexpected success: {response}")
except ftplib.error_perm as e:
# The ftplib library automatically raises an error_perm for 5xx codes
print(f"Caught expected error: {e}")
# The exception message contains the server's response
print(f"Exception message: {str(e)}")
# --- 5. Using a command that requires a data connection (PASV) ---
# The 'LIST' command itself doesn't return the list, it returns a status code.
# The actual data is sent over a separate data connection.
print("\n--- Command: LIST ---")
response = ftp.sendcmd('LIST')
print(f"Raw Response: {response}")
# This will return something like:
# "150 Here comes the directory listing."
# After this, the server sends the directory data, and then a final "226 Transfer complete."
# --- 6. Clean up ---
ftp.quit()
print("\nConnection closed.")
except socket.gaierror:
print("Error: Could not resolve hostname. Is the server address correct?")
except ftplib.all_errors as e:
print(f"An FTP error occurred: {e}")
if 'ftp' in locals() and ftp.sock is not None:
ftp.quit() # Ensure connection is closed if it was opened
Key Points and Best Practices
sendcmd vs. High-Level Methods
| Feature | ftp.sendcmd('LIST') |
ftp.dir() |
|---|---|---|
| Purpose | Low-level command execution. High-level directory listing. | |
| Return Value | Server's raw response string (e.g., "150 ..."). |
None. It prints the directory listing directly to sys.stdout. |
| Data Handling | Only sends the command. You must handle the data connection yourself to get the file list. | Automatically handles the PASV (or PORT) command, creates the data connection, retrieves the data, and prints it. |
| Error Handling | Raises ftplib.error_perm for 5xx errors. |
Raises ftplib.error_perm for 5xx errors. |
| Use Case | When you need fine-grained control, want to see the raw server response, or are implementing a custom FTP operation. | For the common task of getting a directory listing. It's much simpler and safer. |
When to Use sendcmd
You should use sendcmd when:
- You need to execute a command that doesn't have a dedicated helper method in
ftplib. - You need to inspect the exact server response code or message for custom logic.
- You are building a more complex FTP client and need to manage the control channel manually.
When to Avoid sendcmd (Use High-Level Methods Instead)
You should avoid sendcmd and use the built-in methods when:

- You want to list a directory (
dir()ormlsd()). - You want to upload a file (
storbinary(),storlines()). - You want to download a file (
retrbinary(),retrlines()). - You want to change the current directory (
cwd()). - You want to get the size of a file (
size()). - You want to delete a file (
delete()).
These high-level methods are safer, less error-prone, and handle the complexities of data connections for you.
Error Handling
As seen in the example, sendcmd will raise an ftplib.error_perm exception if the server returns a permanent error (5xx code). It will also raise other ftplib exceptions for connection issues or other errors. It's crucial to wrap your FTP logic in a try...except block.
Important FTP Commands to Know
USER <username>: Specify the username.PASS <password>: Specify the password.ACCT <account>: Specify the account (rarely used).CWD <path>: Change the current working directory.CDUP: Change to the parent directory.QUIT: Log out and close the connection.PASV: Enter passive mode. The server tells the client which port to connect to for data transfers.LIST [<path>]: List files in a directory.NLST [<path>]: Get a list of file names only.RETR <filename>: Retrieve a file from the server.STOR <filename>: Store a file on the server.DELE <filename>: Delete a file.SIZE <filename>: Get the size of a file.SYST: Get the system type.TYPE {A, I, E}: Set the transfer type (ASCII, Image/Binary, Ebcdic).
Summary
ftplib.sendcmd is a powerful and direct way to communicate with an FTP server. It's the "speak directly to the server" method. While high-level methods are often sufficient for common tasks, understanding sendcmd is essential for debugging, implementing custom protocols, or handling edge cases that the standard library doesn't cover. Always remember to handle exceptions gracefully when working with network protocols like FTP.
