A 100% pure Java library for the Twitter API with no extra dependency
Private messaging functionality for sending and receiving direct messages.
Send private messages to other Twitter users.
interface DirectMessagesResources {
/**
* Send direct message by user ID
* @param userId Recipient user ID
* @param text Message text (max 10,000 characters)
* @return Sent direct message
*/
DirectMessage sendDirectMessage(long userId, String text) throws TwitterException;
/**
* Send direct message by screen name
* @param screenName Recipient screen name (without @)
* @param text Message text (max 10,000 characters)
* @return Sent direct message
*/
DirectMessage sendDirectMessage(String screenName, String text) throws TwitterException;
/**
* Send direct message with quick reply options
* @param userId Recipient user ID
* @param text Message text
* @param quickReplies Quick reply options
* @return Sent direct message
*/
DirectMessage sendDirectMessage(long userId, String text, QuickReply... quickReplies) throws TwitterException;
/**
* Send direct message as quick reply response
* @param userId Recipient user ID
* @param text Message text
* @param quickReplyResponse Quick reply response metadata
* @return Sent direct message
*/
DirectMessage sendDirectMessage(long userId, String text, String quickReplyResponse) throws TwitterException;
/**
* Send direct message with media attachment
* @param userId Recipient user ID
* @param text Message text
* @param mediaId Media ID from uploadMedia() call
* @return Sent direct message
*/
DirectMessage sendDirectMessage(long userId, String text, long mediaId) throws TwitterException;
}Usage Examples:
TwitterV1 v1 = twitter.v1();
// Send simple text message
DirectMessage dm = v1.directMessages().sendDirectMessage("recipient_user",
"Hello! This is a direct message.");
// Send message by user ID
DirectMessage dmById = v1.directMessages().sendDirectMessage(12345L,
"Hello via user ID!");
// Send message with media
File image = new File("attachment.jpg");
UploadedMedia media = v1.tweets().uploadMedia(image);
DirectMessage dmWithMedia = v1.directMessages().sendDirectMessage(12345L,
"Check out this image!", media.getMediaId());
// Send message with quick reply options
QuickReply option1 = QuickReply.of("yes", "Yes");
QuickReply option2 = QuickReply.of("no", "No");
DirectMessage dmWithOptions = v1.directMessages().sendDirectMessage(12345L,
"Do you like Twitter4J?", option1, option2);Get direct message conversations and individual messages.
interface DirectMessagesResources {
/**
* Get direct messages (both sent and received)
* @param count Number of messages to retrieve (max 50)
* @return List of direct messages
*/
DirectMessageList getDirectMessages(int count) throws TwitterException;
/**
* Get direct messages with cursor pagination
* @param count Number of messages to retrieve (max 50)
* @param cursor Pagination cursor
* @return List of direct messages
*/
DirectMessageList getDirectMessages(int count, String cursor) throws TwitterException;
/**
* Get specific direct message by ID
* @param id Direct message ID
* @return Direct message
*/
DirectMessage showDirectMessage(long id) throws TwitterException;
}Usage Examples:
// Get recent direct messages
DirectMessageList messages = v1.directMessages().getDirectMessages(20);
for (DirectMessage dm : messages.getList()) {
System.out.println("From: " + dm.getSenderScreenName());
System.out.println("Text: " + dm.getText());
System.out.println("Date: " + dm.getCreatedAt());
}
// Paginate through all messages
String cursor = null;
do {
DirectMessageList batch = v1.directMessages().getDirectMessages(50, cursor);
for (DirectMessage dm : batch.getList()) {
processDirectMessage(dm);
}
cursor = batch.getNextCursor();
} while (cursor != null);
// Get specific message
DirectMessage specificDM = v1.directMessages().showDirectMessage(987654321L);Delete direct messages from conversations.
interface DirectMessagesResources {
/**
* Delete a direct message
* @param id Direct message ID to delete
*/
void destroyDirectMessage(long id) throws TwitterException;
}Usage Example:
// Delete a direct message
v1.directMessages().destroyDirectMessage(987654321L);
System.out.println("Direct message deleted");Download media attachments from direct messages.
interface DirectMessagesResources {
/**
* Get direct message image as input stream
* @param url Media URL from DirectMessage
* @return InputStream of image data
*/
InputStream getDMImageAsStream(String url) throws TwitterException;
}Usage Example:
DirectMessage dm = v1.directMessages().showDirectMessage(messageId);
// Check if message has media
if (dm.getMediaEntities().length > 0) {
MediaEntity media = dm.getMediaEntities()[0];
// Download the media
try (InputStream mediaStream = v1.directMessages().getDMImageAsStream(media.getMediaURL())) {
// Save to file
Files.copy(mediaStream, Paths.get("dm_image.jpg"));
}
}Add interactive quick reply buttons to direct messages.
class QuickReply {
/**
* Create quick reply option
* @param value Value returned when selected
* @param label Display text for button
* @return QuickReply option
*/
static QuickReply of(String value, String label);
/**
* Create quick reply with description
* @param value Value returned when selected
* @param label Display text for button
* @param description Additional description text
* @return QuickReply option
*/
static QuickReply of(String value, String label, String description);
/**
* Create quick reply with media
* @param value Value returned when selected
* @param label Display text for button
* @param mediaUrl URL of media to display
* @return QuickReply option
*/
static QuickReply withMedia(String value, String label, String mediaUrl);
/**
* Get option value
*/
String getValue();
/**
* Get display label
*/
String getLabel();
/**
* Get description text
*/
String getDescription();
/**
* Get media URL
*/
String getMediaUrl();
}Quick Reply Examples:
// Simple yes/no options
QuickReply yes = QuickReply.of("confirm_yes", "Yes");
QuickReply no = QuickReply.of("confirm_no", "No");
v1.directMessages().sendDirectMessage(userId,
"Would you like to receive notifications?", yes, no);
// Options with descriptions
QuickReply basic = QuickReply.of("plan_basic", "Basic", "$9.99/month");
QuickReply premium = QuickReply.of("plan_premium", "Premium", "$19.99/month");
QuickReply enterprise = QuickReply.of("plan_enterprise", "Enterprise", "Contact sales");
v1.directMessages().sendDirectMessage(userId,
"Choose your plan:", basic, premium, enterprise);
// Options with media
QuickReply red = QuickReply.withMedia("color_red", "Red", "https://example.com/red.png");
QuickReply blue = QuickReply.withMedia("color_blue", "Blue", "https://example.com/blue.png");
v1.directMessages().sendDirectMessage(userId,
"Pick your favorite color:", red, blue);Complete direct message data structure.
interface DirectMessage extends TwitterResponse {
/**
* Message unique identifier
*/
long getId();
/**
* Message text content
*/
String getText();
/**
* Sender user ID
*/
long getSenderId();
/**
* Sender screen name
*/
String getSenderScreenName();
/**
* Recipient user ID
*/
long getRecipientId();
/**
* Recipient screen name
*/
String getRecipientScreenName();
/**
* Message creation timestamp
*/
LocalDateTime getCreatedAt();
/**
* Quick reply options attached to message
*/
QuickReply[] getQuickReplies();
/**
* Quick reply response metadata (if this is a response)
*/
String getQuickReplyResponse();
/**
* URL entities in message text
*/
URLEntity[] getURLEntities();
/**
* User mention entities in message text
*/
UserMentionEntity[] getUserMentionEntities();
/**
* Hashtag entities in message text
*/
HashtagEntity[] getHashtagEntities();
/**
* Media entities (images, videos) attached to message
*/
MediaEntity[] getMediaEntities();
/**
* Symbol entities (cashtags) in message text
*/
SymbolEntity[] getSymbolEntities();
}Paginated list of direct messages.
interface DirectMessageList extends TwitterResponse {
/**
* List of direct messages
*/
List<DirectMessage> getList();
/**
* Next cursor for pagination (null if no more)
*/
String getNextCursor();
/**
* Previous cursor for pagination
*/
String getPreviousCursor();
}public class DMConversationManager {
private final TwitterV1 v1;
public Map<String, List<DirectMessage>> getConversationsByUser() throws TwitterException {
DirectMessageList allMessages = v1.directMessages().getDirectMessages(50);
return allMessages.getList().stream()
.collect(Collectors.groupingBy(
dm -> getConversationKey(dm),
Collectors.toList()
));
}
private String getConversationKey(DirectMessage dm) {
// Create unique key for conversation between two users
long currentUserId = getCurrentUserId(); // Your implementation
long otherUserId = (dm.getSenderId() == currentUserId) ?
dm.getRecipientId() : dm.getSenderId();
return Math.min(currentUserId, otherUserId) + "_" +
Math.max(currentUserId, otherUserId);
}
}public class DMAutoResponder {
private final TwitterV1 v1;
private final Map<String, String> responses;
public DMAutoResponder(TwitterV1 v1) {
this.v1 = v1;
this.responses = Map.of(
"help", "Here are the available commands: help, status, info",
"status", "All systems operational!",
"info", "This is an automated response system."
);
}
public void processQuickReplyResponse(DirectMessage dm) throws TwitterException {
String response = dm.getQuickReplyResponse();
if (response != null && responses.containsKey(response)) {
v1.directMessages().sendDirectMessage(
dm.getSenderId(),
responses.get(response)
);
}
}
public void handleTextMessage(DirectMessage dm) throws TwitterException {
String text = dm.getText().toLowerCase().trim();
if (responses.containsKey(text)) {
v1.directMessages().sendDirectMessage(
dm.getSenderId(),
responses.get(text)
);
} else {
// Send help with quick reply options
QuickReply help = QuickReply.of("help", "Help");
QuickReply status = QuickReply.of("status", "Status");
v1.directMessages().sendDirectMessage(
dm.getSenderId(),
"I didn't understand that. How can I help?",
help, status
);
}
}
}public class BulkDMOperations {
private final TwitterV1 v1;
public void sendBulkMessage(List<Long> userIds, String message) throws TwitterException {
for (long userId : userIds) {
try {
v1.directMessages().sendDirectMessage(userId, message);
// Rate limiting - DM endpoint allows 1000 requests per 24 hours
Thread.sleep(100); // Small delay between messages
} catch (TwitterException e) {
if (e.getStatusCode() == 403) {
System.err.println("Cannot send DM to user " + userId + ": " + e.getMessage());
} else {
throw e; // Re-throw other errors
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
}
public void deleteAllMessagesFromUser(long userId) throws TwitterException {
DirectMessageList messages = v1.directMessages().getDirectMessages(50);
List<DirectMessage> toDelete = messages.getList().stream()
.filter(dm -> dm.getSenderId() == userId || dm.getRecipientId() == userId)
.collect(Collectors.toList());
for (DirectMessage dm : toDelete) {
try {
v1.directMessages().destroyDirectMessage(dm.getId());
Thread.sleep(100); // Rate limiting
} catch (TwitterException e) {
System.err.println("Failed to delete message " + dm.getId() + ": " + e.getMessage());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
}
}Direct message operations can fail for various reasons:
try {
DirectMessage dm = v1.directMessages().sendDirectMessage("user", "Hello!");
} catch (TwitterException e) {
switch (e.getStatusCode()) {
case 403:
if (e.getErrorCode() == 150) {
System.out.println("Cannot send DM: user doesn't follow you");
} else if (e.getErrorCode() == 151) {
System.out.println("Cannot send DM: user has disabled DMs");
} else {
System.out.println("Forbidden: " + e.getMessage());
}
break;
case 404:
System.out.println("User not found or account suspended");
break;
case 429:
System.out.println("Rate limit exceeded - DM limit reached");
break;
default:
System.out.println("Error sending DM: " + e.getMessage());
}
}Install with Tessl CLI
npx tessl i tessl/maven-org-twitter4j--twitter4j-core