Skip to content

Commit

Permalink
Provide POP3 support, close #63
Browse files Browse the repository at this point in the history
  • Loading branch information
Robert Virkus committed Jun 2, 2020
1 parent 0d72d57 commit 33e66b7
Show file tree
Hide file tree
Showing 35 changed files with 800 additions and 48 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## 0.0.23
- Provide [POP3](https://tools.ietf.org/html/rfc1939) support

## 0.0.22
- Breaking API change: use FETCH IMAP methods now return `FetchImapResult` instead of `List<MimeMessage>`
- Breaking API change: `ImapFetchEvent` now contains a full `MimeMessage` instead of just the sequence ID and flags
Expand Down
93 changes: 71 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,30 @@ A simple usage example:
import 'dart:io';
import 'package:enough_mail/enough_mail.dart';
String userName = 'user.name';
String password = 'password';
String imapServerHost = 'imap.domain.com';
int imapServerPort = 993;
bool isImapServerSecure = true;
String popServerHost = 'pop.domain.com';
int popServerPort = 995;
bool isPopServerSecure = true;
String smtpServerHost = 'smtp.domain.com';
int smtpServerPort = 465;
bool isSmtpServerSecure = true;
void main() async {
await imapExample();
await smtpExample();
await popExample();
exit(0);
}
Future<void> imapExample() async {
var client = ImapClient(isLogEnabled: false);
await client.connectToServer('imap.domain.com', 993, isSecure: true);
var loginResponse = await client.login('user.name', 'password');
await client.connectToServer(imapServerHost, imapServerPort,
isSecure: isImapServerSecure);
var loginResponse = await client.login(userName, password);
if (loginResponse.isOkStatus) {
var listResponse = await client.listMailboxes();
if (listResponse.isOkStatus) {
Expand All @@ -34,23 +48,7 @@ Future<void> imapExample() async {
if (fetchResponse.isOkStatus) {
var messages = fetchResponse.result.messages;
for (var message in messages) {
print(
'from: ${message.from} with subject "${message.decodeSubject()}"');
if (!message.isTextPlainMessage()) {
print(' content-type: ${message.mediaType}');
} else {
var plainText = message.decodeTextPlainPart();
if (plainText != null) {
var lines = plainText.split('\r\n');
for (var line in lines) {
if (line.startsWith('>')) {
// break when quoted text starts
break;
}
print(line);
}
}
}
printMessage(message);
}
}
}
Expand All @@ -60,7 +58,8 @@ Future<void> imapExample() async {
Future<void> smtpExample() async {
var client = SmtpClient('enough.de', isLogEnabled: true);
await client.connectToServer('smtp.domain.com', 465, isSecure: true);
await client.connectToServer(smtpServerHost, smtpServerPort,
isSecure: isSmtpServerSecure);
var ehloResponse = await client.ehlo();
if (!ehloResponse.isOkStatus) {
print('SMTP: unable to say helo/ehlo: ${ehloResponse.message}');
Expand All @@ -79,14 +78,64 @@ Future<void> smtpExample() async {
print('message sent: ${sendResponse.isOkStatus}');
}
}
Future<void> popExample() async {
var client = PopClient(isLogEnabled: false);
await client.connectToServer(popServerHost, popServerPort,
isSecure: isPopServerSecure);
var loginResponse = await client.login(userName, password);
//var loginResponse = await client.loginWithApop(userName, password); // optional different login mechanism
if (loginResponse.isOkStatus) {
var statusResponse = await client.status();
if (statusResponse.isOkStatus) {
print(
'status: messages count=${statusResponse.result.numberOfMessages}, messages size=${statusResponse.result.totalSizeInBytes}');
var listResponse =
await client.list(statusResponse.result.numberOfMessages);
print(
'last message: id=${listResponse.result?.first?.id} size=${listResponse.result?.first?.sizeInBytes}');
var retrieveResponse =
await client.retrieve(statusResponse.result.numberOfMessages);
if (retrieveResponse.isOkStatus) {
printMessage(retrieveResponse.result);
} else {
print('last message could not be retrieved');
}
retrieveResponse =
await client.retrieve(statusResponse.result.numberOfMessages + 1);
print(
'trying to retrieve newer message succeeded: ${retrieveResponse.isOkStatus}');
}
}
await client.quit();
}
void printMessage(MimeMessage message) {
print('from: ${message.from} with subject "${message.decodeSubject()}"');
if (!message.isTextPlainMessage()) {
print(' content-type: ${message.mediaType}');
} else {
var plainText = message.decodeTextPlainPart();
if (plainText != null) {
var lines = plainText.split('\r\n');
for (var line in lines) {
if (line.startsWith('>')) {
// break when quoted text starts
break;
}
print(line);
}
}
}
}
```

## Installation
Add this dependency your pubspec.yaml file:

```
dependencies:
enough_mail: ^0.0.22
enough_mail: ^0.0.23
```
The latest version or `enough_mail` is [![enough_mail version](https://img.shields.io/pub/v/enough_mail.svg)](https://pub.dartlang.org/packages/enough_mail).

Expand All @@ -102,6 +151,7 @@ Want to contribute? Please check out [contribute](https://github.com/Enough-Soft
### Done
*[IMAP4 rev1](https://tools.ietf.org/html/rfc3501) support
* ✅ basic [SMTP](https://tools.ietf.org/html/rfc5321) support
*[POP3](https://tools.ietf.org/html/rfc1939) support
*[MIME](https://tools.ietf.org/html/rfc2045) parsing and generation support

The following IMAP extensions are supported:
Expand Down Expand Up @@ -132,7 +182,6 @@ Transfer encodings:
* support [Message Preview Generation](https://datatracker.ietf.org/doc/draft-ietf-extra-imap-fetch-preview/)
* support [WebPush IMAP Extension](https://github.com/coi-dev/coi-specs/blob/master/webpush-spec.md)
* support [Open PGP](https://tools.ietf.org/html/rfc4880)
* support [POP3](https://tools.ietf.org/html/rfc1939)

### Develop and Contribute
* To start check out the package and then run `pub run test` to run all tests.
Expand Down
89 changes: 69 additions & 20 deletions example/enough_mail_example.dart
Original file line number Diff line number Diff line change
@@ -1,16 +1,30 @@
import 'dart:io';
import 'package:enough_mail/enough_mail.dart';

String userName = 'user.name';
String password = 'password';
String imapServerHost = 'imap.domain.com';
int imapServerPort = 993;
bool isImapServerSecure = true;
String popServerHost = 'pop.domain.com';
int popServerPort = 995;
bool isPopServerSecure = true;
String smtpServerHost = 'smtp.domain.com';
int smtpServerPort = 465;
bool isSmtpServerSecure = true;

void main() async {
await imapExample();
await smtpExample();
await popExample();
exit(0);
}

Future<void> imapExample() async {
var client = ImapClient(isLogEnabled: false);
await client.connectToServer('imap.domain.com', 993, isSecure: true);
var loginResponse = await client.login('user.name', 'password');
await client.connectToServer(imapServerHost, imapServerPort,
isSecure: isImapServerSecure);
var loginResponse = await client.login(userName, password);
if (loginResponse.isOkStatus) {
var listResponse = await client.listMailboxes();
if (listResponse.isOkStatus) {
Expand All @@ -24,23 +38,7 @@ Future<void> imapExample() async {
if (fetchResponse.isOkStatus) {
var messages = fetchResponse.result.messages;
for (var message in messages) {
print(
'from: ${message.from} with subject "${message.decodeSubject()}"');
if (!message.isTextPlainMessage()) {
print(' content-type: ${message.mediaType}');
} else {
var plainText = message.decodeTextPlainPart();
if (plainText != null) {
var lines = plainText.split('\r\n');
for (var line in lines) {
if (line.startsWith('>')) {
// break when quoted text starts
break;
}
print(line);
}
}
}
printMessage(message);
}
}
}
Expand All @@ -50,7 +48,8 @@ Future<void> imapExample() async {

Future<void> smtpExample() async {
var client = SmtpClient('enough.de', isLogEnabled: true);
await client.connectToServer('smtp.domain.com', 465, isSecure: true);
await client.connectToServer(smtpServerHost, smtpServerPort,
isSecure: isSmtpServerSecure);
var ehloResponse = await client.ehlo();
if (!ehloResponse.isOkStatus) {
print('SMTP: unable to say helo/ehlo: ${ehloResponse.message}');
Expand All @@ -69,3 +68,53 @@ Future<void> smtpExample() async {
print('message sent: ${sendResponse.isOkStatus}');
}
}

Future<void> popExample() async {
var client = PopClient(isLogEnabled: false);
await client.connectToServer(popServerHost, popServerPort,
isSecure: isPopServerSecure);
var loginResponse = await client.login(userName, password);
//var loginResponse = await client.loginWithApop(userName, password); // optional different login mechanism
if (loginResponse.isOkStatus) {
var statusResponse = await client.status();
if (statusResponse.isOkStatus) {
print(
'status: messages count=${statusResponse.result.numberOfMessages}, messages size=${statusResponse.result.totalSizeInBytes}');
var listResponse =
await client.list(statusResponse.result.numberOfMessages);
print(
'last message: id=${listResponse.result?.first?.id} size=${listResponse.result?.first?.sizeInBytes}');
var retrieveResponse =
await client.retrieve(statusResponse.result.numberOfMessages);
if (retrieveResponse.isOkStatus) {
printMessage(retrieveResponse.result);
} else {
print('last message could not be retrieved');
}
retrieveResponse =
await client.retrieve(statusResponse.result.numberOfMessages + 1);
print(
'trying to retrieve newer message succeeded: ${retrieveResponse.isOkStatus}');
}
}
await client.quit();
}

void printMessage(MimeMessage message) {
print('from: ${message.from} with subject "${message.decodeSubject()}"');
if (!message.isTextPlainMessage()) {
print(' content-type: ${message.mediaType}');
} else {
var plainText = message.decodeTextPlainPart();
if (plainText != null) {
var lines = plainText.split('\r\n');
for (var line in lines) {
if (line.startsWith('>')) {
// break when quoted text starts
break;
}
print(line);
}
}
}
}
4 changes: 4 additions & 0 deletions lib/enough_mail.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ export 'imap/message_sequence.dart';
export 'imap/metadata.dart';
export 'imap/qresync.dart';

export 'pop/pop_client.dart';
export 'pop/pop_events.dart';
export 'pop/pop_response.dart';

export 'smtp/smtp_client.dart';
export 'smtp/smtp_response.dart';
export 'smtp/smtp_events.dart';
Expand Down
Loading

0 comments on commit 33e66b7

Please sign in to comment.