diff --git a/examples/servers/imap_example.vsh b/examples/servers/imap_example.vsh
deleted file mode 100755
index 968c5250..00000000
--- a/examples/servers/imap_example.vsh
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/usr/bin/env -S v -n -w -cg -gc none -cc tcc -d use_openssl -enable-globals run
-
-import freeflowuniverse.herolib.servers.mail.server
-
-// Start the IMAP server on port 143
-server.start_demo() !
\ No newline at end of file
diff --git a/lib/servers/calendar/calbox/alarm.v b/lib/servers/calendar/calbox/alarm.v
deleted file mode 100644
index f5daba19..00000000
--- a/lib/servers/calendar/calbox/alarm.v
+++ /dev/null
@@ -1,39 +0,0 @@
-module calbox
-
-// Represents an alarm/reminder
-@[heap]
-pub struct Alarm {
-pub mut:
- action AlarmAction
- trigger string // When the alarm triggers (relative or absolute)
- description string // Used for DISPLAY and EMAIL
- summary string // Used for EMAIL
- attendees []Attendee // Used for EMAIL
- attach []string // Used for AUDIO and EMAIL attachments
-}
-
-// Alarm action types
-pub enum AlarmAction {
- audio // Play a sound
- display // Display a message
- email // Send an email
-}
-
-// String representation of alarm action
-pub fn (a AlarmAction) str() string {
- return match a {
- .audio { 'AUDIO' }
- .display { 'DISPLAY' }
- .email { 'EMAIL' }
- }
-}
-
-// Parse alarm action from string
-pub fn parse_alarm_action(s string) !AlarmAction {
- return match s {
- 'AUDIO' { AlarmAction.audio }
- 'DISPLAY' { AlarmAction.display }
- 'EMAIL' { AlarmAction.email }
- else { error('Invalid alarm action: ${s}') }
- }
-}
diff --git a/lib/servers/calendar/calbox/attendee.v b/lib/servers/calendar/calbox/attendee.v
deleted file mode 100644
index 522139a7..00000000
--- a/lib/servers/calendar/calbox/attendee.v
+++ /dev/null
@@ -1,75 +0,0 @@
-module calbox
-
-// Represents a calendar attendee
-@[heap]
-pub struct Attendee {
-pub mut:
- email string
- name string
- role AttendeeRole
- partstat AttendeePartStat
- rsvp bool
- delegated_to []string
- delegated_from []string
-}
-
-// Attendee role types
-pub enum AttendeeRole {
- chair // Meeting chair/organizer
- req_participant // Required participant
- opt_participant // Optional participant
- non_participant // Non-participant (e.g. room, resource)
-}
-
-// String representation of attendee role
-pub fn (r AttendeeRole) str() string {
- return match r {
- .chair { 'CHAIR' }
- .req_participant { 'REQ-PARTICIPANT' }
- .opt_participant { 'OPT-PARTICIPANT' }
- .non_participant { 'NON-PARTICIPANT' }
- }
-}
-
-// Parse attendee role from string
-pub fn parse_attendee_role(s string) !AttendeeRole {
- return match s {
- 'CHAIR' { AttendeeRole.chair }
- 'REQ-PARTICIPANT' { AttendeeRole.req_participant }
- 'OPT-PARTICIPANT' { AttendeeRole.opt_participant }
- 'NON-PARTICIPANT' { AttendeeRole.non_participant }
- else { error('Invalid attendee role: ${s}') }
- }
-}
-
-// Attendee participation status
-pub enum AttendeePartStat {
- needs_action // No response yet
- accepted // Accepted invitation
- declined // Declined invitation
- tentative // Tentatively accepted
- delegated // Delegated to another
-}
-
-// String representation of participation status
-pub fn (p AttendeePartStat) str() string {
- return match p {
- .needs_action { 'NEEDS-ACTION' }
- .accepted { 'ACCEPTED' }
- .declined { 'DECLINED' }
- .tentative { 'TENTATIVE' }
- .delegated { 'DELEGATED' }
- }
-}
-
-// Parse participation status from string
-pub fn parse_attendee_partstat(s string) !AttendeePartStat {
- return match s {
- 'NEEDS-ACTION' { AttendeePartStat.needs_action }
- 'ACCEPTED' { AttendeePartStat.accepted }
- 'DECLINED' { AttendeePartStat.declined }
- 'TENTATIVE' { AttendeePartStat.tentative }
- 'DELEGATED' { AttendeePartStat.delegated }
- else { error('Invalid participation status: ${s}') }
- }
-}
diff --git a/lib/servers/calendar/calbox/calendar.v b/lib/servers/calendar/calbox/calendar.v
deleted file mode 100644
index 029fc986..00000000
--- a/lib/servers/calendar/calbox/calendar.v
+++ /dev/null
@@ -1,354 +0,0 @@
-module calbox
-
-// Represents a calendar collection
-@[heap]
-pub struct Calendar {
-mut:
- name string
- objects []CalendarItem
- description string
- timezone string // Calendar timezone as iCalendar VTIMEZONE
- read_only bool // Whether calendar is read-only
-
- // Properties from CalDAV spec
- supported_components []ComponentType // e.g. [.vevent, .vtodo]
- min_date_time string // Earliest date allowed
- max_date_time string // Latest date allowed
- max_instances int // Max recurrence instances
- max_attendees int // Max attendees per instance
- max_resource_size int // Max size of calendar object
-}
-
-// Creates a new calendar collection
-pub fn new(name string) &Calendar {
- return &Calendar{
- name: name
- objects: []CalendarItem{}
- supported_components: [ComponentType.vevent, ComponentType.vtodo, ComponentType.vjournal]
- min_date_time: '19000101T000000Z'
- max_date_time: '20491231T235959Z'
- max_instances: 1000
- max_attendees: 100
- max_resource_size: 1024 * 1024 // 1MB
- }
-}
-
-// Returns all calendar objects
-pub fn (mut self Calendar) list() ![]CalendarItem {
- return self.objects
-}
-
-// Gets a calendar object by UID
-pub fn (mut self Calendar) get_by_uid(uid string) ?CalendarItem {
- for obj in self.objects {
- match obj.comp_type {
- .vevent {
- if obj.event?.uid == uid {
- return obj
- }
- }
- .vtodo {
- if obj.todo?.uid == uid {
- return obj
- }
- }
- .vjournal {
- if obj.journal?.uid == uid {
- return obj
- }
- }
- }
- }
- return none
-}
-
-// Deletes a calendar object by UID
-pub fn (mut self Calendar) delete(uid string) ! {
- if self.read_only {
- return error('Calendar is read-only')
- }
-
- for i, obj in self.objects {
- mut found := false
- match obj.comp_type {
- .vevent {
- if event := obj.event {
- found = event.uid == uid
- }
- }
- .vtodo {
- if todo := obj.todo {
- found = todo.uid == uid
- }
- }
- .vjournal {
- if journal := obj.journal {
- found = journal.uid == uid
- }
- }
- }
- if found {
- self.objects.delete(i)
- return
- }
- }
- return error('Calendar object with UID ${uid} not found')
-}
-
-// Validates a calendar object
-fn (mut self Calendar) validate(obj CalendarItem) ! {
- // Validate component type is supported
- if obj.comp_type !in self.supported_components {
- return error('Calendar component type ${obj.comp_type} not supported')
- }
-
- // Validate based on component type
- match obj.comp_type {
- .vevent {
- event := obj.event or { return error('VEVENT component missing') }
-
- // Validate required fields
- if event.uid.len == 0 {
- return error('UID is required')
- }
- if event.start_time == 0 {
- return error('Start time is required')
- }
- if event.end_time == none && event.duration == none {
- return error('Either end time or duration is required')
- }
-
- // Validate attendees count
- if event.attendees.len > self.max_attendees {
- return error('Exceeds maximum attendees limit of ${self.max_attendees}')
- }
-
- // Validate recurrence
- if event.rrule != none {
- // TODO: Validate max instances once recurrence expansion is implemented
- }
- }
- .vtodo {
- todo := obj.todo or { return error('VTODO component missing') }
-
- // Validate required fields
- if todo.uid.len == 0 {
- return error('UID is required')
- }
-
- // Validate attendees count
- if todo.attendees.len > self.max_attendees {
- return error('Exceeds maximum attendees limit of ${self.max_attendees}')
- }
- }
- .vjournal {
- journal := obj.journal or { return error('VJOURNAL component missing') }
-
- // Validate required fields
- if journal.uid.len == 0 {
- return error('UID is required')
- }
- if journal.start_time == 0 {
- return error('Start time is required')
- }
-
- // Validate attendees count
- if journal.attendees.len > self.max_attendees {
- return error('Exceeds maximum attendees limit of ${self.max_attendees}')
- }
- }
- }
-}
-
-// Adds or updates a calendar object
-pub fn (mut self Calendar) put(obj CalendarItem) ! {
- if self.read_only {
- return error('Calendar is read-only')
- }
-
- // Validate the object
- self.validate(obj) or { return err }
-
- mut found := false
- for i, existing in self.objects {
- mut match_uid := false
- match obj.comp_type {
- .vevent {
- if e1 := obj.event {
- if e2 := existing.event {
- match_uid = e1.uid == e2.uid
- }
- }
- }
- .vtodo {
- if t1 := obj.todo {
- if t2 := existing.todo {
- match_uid = t1.uid == t2.uid
- }
- }
- }
- .vjournal {
- if j1 := obj.journal {
- if j2 := existing.journal {
- match_uid = j1.uid == j2.uid
- }
- }
- }
- }
- if match_uid {
- self.objects[i] = obj
- found = true
- break
- }
- }
-
- if !found {
- self.objects << obj
- }
-}
-
-// Checks if a journal entry overlaps with a time range
-fn (journal Journal) overlaps(tr TimeRange) bool {
- return is_in_range(journal.start_time, tr)
-}
-
-// Finds calendar objects in the given time range
-pub fn (mut self Calendar) find_by_time(tr TimeRange) ![]CalendarItem {
- mut results := []CalendarItem{}
-
- for obj in self.objects {
- match obj.comp_type {
- .vevent {
- if event := obj.event {
- // Get all instances in the time range
- instances := event.get_instances(tr)!
- if instances.len > 0 {
- results << obj
- }
- }
- }
- .vtodo {
- if todo := obj.todo {
- // Check todo timing
- mut overlaps := false
-
- // Check start time if set
- if start := todo.start_time {
- if is_in_range(start, tr) {
- overlaps = true
- }
- }
-
- // Check due time if set
- if due := todo.due_time {
- if is_in_range(due, tr) {
- overlaps = true
- }
- }
-
- // Check completed time if set
- if completed := todo.completed {
- if is_in_range(completed, tr) {
- overlaps = true
- }
- }
-
- // If no timing info, include if created in range
- if todo.start_time == none && todo.due_time == none && todo.completed == none {
- if is_in_range(todo.created, tr) {
- overlaps = true
- }
- }
-
- if overlaps {
- results << obj
- }
- }
- }
- .vjournal {
- if journal := obj.journal {
- // Journal entries are point-in-time
- if is_in_range(journal.start_time, tr) {
- results << obj
- }
- }
- }
- }
- }
-
- return results
-}
-
-// Gets all instances of calendar objects in a time range
-pub fn (mut self Calendar) get_instances(tr TimeRange) ![]EventInstance {
- mut instances := []EventInstance{}
-
- for obj in self.objects {
- if obj.comp_type == .vevent {
- if event := obj.event {
- event_instances := event.get_instances(tr)!
- instances << event_instances
- }
- }
- }
-
- // Sort by start time
- instances.sort(a.start_time < b.start_time)
-
- return instances
-}
-
-// Gets free/busy time in a given range
-pub fn (mut self Calendar) get_freebusy(tr TimeRange) ![]TimeRange {
- mut busy_ranges := []TimeRange{}
-
- // Get all event instances in the range
- instances := self.get_instances(tr)!
-
- // Convert instances to busy time ranges
- for instance in instances {
- // Skip transparent events
- if instance.original_event.transp == .transparent {
- continue
- }
-
- // Skip cancelled events
- if instance.original_event.status == .cancelled {
- continue
- }
-
- busy_ranges << TimeRange{
- start: instance.start_time
- end: instance.end_time
- }
- }
-
- // Merge overlapping ranges
- if busy_ranges.len > 0 {
- busy_ranges.sort(a.start < b.start)
- mut merged := []TimeRange{}
- mut current := busy_ranges[0]
-
- for i := 1; i < busy_ranges.len; i++ {
- if busy_ranges[i].start <= current.end {
- // Ranges overlap, extend current range
- if busy_ranges[i].end > current.end {
- current.end = busy_ranges[i].end
- }
- } else {
- // No overlap, start new range
- merged << current
- current = busy_ranges[i]
- }
- }
- merged << current
- return merged
- }
-
- return busy_ranges
-}
-
-// Returns number of calendar objects
-pub fn (mut self Calendar) len() int {
- return self.objects.len
-}
diff --git a/lib/servers/calendar/calbox/calendar_component.v b/lib/servers/calendar/calbox/calendar_component.v
deleted file mode 100644
index 5dc87555..00000000
--- a/lib/servers/calendar/calbox/calendar_component.v
+++ /dev/null
@@ -1,94 +0,0 @@
-module calbox
-
-// Base calendar component fields
-@[heap]
-pub struct CalendarComponent {
-pub mut:
- uid string
- etag string // Entity tag for change tracking
- created i64 // Creation timestamp
- modified i64 // Last modified timestamp
- summary string
- description string
- categories []string
- status ComponentStatus
- class ComponentClass
- url string
- location string
- geo ?GeoLocation
- alarms []Alarm
-}
-
-// Geographic location
-pub struct GeoLocation {
-pub mut:
- latitude f64
- longitude f64
-}
-
-// Calendar component status
-pub enum ComponentStatus {
- tentative // Tentatively scheduled
- confirmed // Confirmed
- cancelled // Cancelled/deleted
- needs_action // Todo needs action
- completed // Todo completed
- in_process // Todo in progress
- draft // Journal draft
- final // Journal final
-}
-
-// String representation of component status
-pub fn (s ComponentStatus) str() string {
- return match s {
- .tentative { 'TENTATIVE' }
- .confirmed { 'CONFIRMED' }
- .cancelled { 'CANCELLED' }
- .needs_action { 'NEEDS-ACTION' }
- .completed { 'COMPLETED' }
- .in_process { 'IN-PROCESS' }
- .draft { 'DRAFT' }
- .final { 'FINAL' }
- }
-}
-
-// Parse component status from string
-pub fn parse_component_status(s string) !ComponentStatus {
- return match s {
- 'TENTATIVE' { ComponentStatus.tentative }
- 'CONFIRMED' { ComponentStatus.confirmed }
- 'CANCELLED' { ComponentStatus.cancelled }
- 'NEEDS-ACTION' { ComponentStatus.needs_action }
- 'COMPLETED' { ComponentStatus.completed }
- 'IN-PROCESS' { ComponentStatus.in_process }
- 'DRAFT' { ComponentStatus.draft }
- 'FINAL' { ComponentStatus.final }
- else { error('Invalid component status: ${s}') }
- }
-}
-
-// Calendar component class (visibility/privacy)
-pub enum ComponentClass {
- public // Visible to everyone
- private // Only visible to owner
- confidential // Limited visibility
-}
-
-// String representation of component class
-pub fn (c ComponentClass) str() string {
- return match c {
- .public { 'PUBLIC' }
- .private { 'PRIVATE' }
- .confidential { 'CONFIDENTIAL' }
- }
-}
-
-// Parse component class from string
-pub fn parse_component_class(s string) !ComponentClass {
- return match s {
- 'PUBLIC' { ComponentClass.public }
- 'PRIVATE' { ComponentClass.private }
- 'CONFIDENTIAL' { ComponentClass.confidential }
- else { error('Invalid component class: ${s}') }
- }
-}
diff --git a/lib/servers/calendar/calbox/calendar_item.v b/lib/servers/calendar/calbox/calendar_item.v
deleted file mode 100644
index b94c208b..00000000
--- a/lib/servers/calendar/calbox/calendar_item.v
+++ /dev/null
@@ -1,18 +0,0 @@
-module calbox
-
-// Represents a calendar object resource (event, todo, journal)
-@[heap]
-pub struct CalendarItem {
-pub mut:
- comp_type ComponentType // Type of calendar component : vevent, vtodo, vjournal
- event ?Event // Set if comp_type is .vevent
- todo ?Todo // Set if comp_type is .vtodo
- journal ?Journal // Set if comp_type is .vjournal
-}
-
-// Component type enum
-pub enum ComponentType {
- vevent
- vtodo
- vjournal
-}
diff --git a/lib/servers/calendar/calbox/calendar_test.v b/lib/servers/calendar/calbox/calendar_test.v
deleted file mode 100644
index a28d26f3..00000000
--- a/lib/servers/calendar/calbox/calendar_test.v
+++ /dev/null
@@ -1,267 +0,0 @@
-module calbox
-
-fn test_create_event() {
- mut cal := new('test_calendar')
-
- // Create an event with all fields
- event := Event{
- CalendarComponent: CalendarComponent{
- uid: 'event1@example.com'
- etag: '"1"'
- created: 1708070400 // 2024-02-16 09:00:00 UTC
- modified: 1708070400
- summary: 'Team Meeting'
- description: 'Weekly team sync'
- categories: ['Work', 'Meeting']
- status: .confirmed
- class: .public
- location: 'Conference Room'
- alarms: [
- Alarm{
- action: .display
- trigger: '-PT15M'
- description: 'Meeting starts in 15 minutes'
- },
- ]
- }
- start_time: 1708074000 // 2024-02-16 10:00:00 UTC
- end_time: 1708077600 // 2024-02-16 11:00:00 UTC
- transp: .opaque
- attendees: [
- Attendee{
- email: 'john@example.com'
- name: 'John Doe'
- role: .req_participant
- partstat: .accepted
- rsvp: true
- },
- Attendee{
- email: 'jane@example.com'
- name: 'Jane Smith'
- role: .req_participant
- partstat: .needs_action
- rsvp: true
- },
- ]
- organizer: Attendee{
- email: 'boss@example.com'
- name: 'The Boss'
- role: .chair
- partstat: .accepted
- }
- }
-
- obj := CalendarItem{
- comp_type: .vevent
- event: event
- }
-
- cal.put(obj) or { panic(err) }
- assert cal.len() == 1
-
- // Verify retrieval
- found := cal.get_by_uid('event1@example.com') or { panic(err) }
- assert found.comp_type == .vevent
-
- if e := found.event {
- assert e.summary == 'Team Meeting'
- assert e.start_time == 1708074000
- assert e.end_time? == 1708077600
- assert e.attendees.len == 2
- assert e.organizer?.email == 'boss@example.com'
- } else {
- assert false, 'Event not found'
- }
-}
-
-fn test_create_recurring_event() {
- mut cal := new('test_calendar')
-
- // Create a daily recurring event
- event := Event{
- CalendarComponent: CalendarComponent{
- uid: 'recurring@example.com'
- etag: '"1"'
- created: 1708070400
- modified: 1708070400
- summary: 'Daily Standup'
- }
- start_time: 1708074000 // 2024-02-16 10:00:00 UTC
- duration: 'PT30M' // 30 minutes
- rrule: RecurrenceRule{
- frequency: .daily
- interval: 1
- count: 5
- }
- }
-
- obj := CalendarItem{
- comp_type: .vevent
- event: event
- }
-
- cal.put(obj) or { panic(err) }
-
- // Test time range search
- tr := TimeRange{
- start: 1708160400 // 2024-02-17 10:00:00 UTC
- end: 1708333200 // 2024-02-19 10:00:00 UTC
- }
-
- results := cal.find_by_time(tr) or { panic(err) }
- assert results.len == 1 // Should find the recurring event
-}
-
-fn test_create_todo() {
- mut cal := new('test_calendar')
-
- // Create a todo with due date
- todo := Todo{
- CalendarComponent: CalendarComponent{
- uid: 'todo1@example.com'
- etag: '"1"'
- created: 1708070400
- modified: 1708070400
- summary: 'Write Documentation'
- status: .needs_action
- }
- due_time: 1708160400 // 2024-02-17 10:00:00 UTC
- percent: 0
- }
-
- obj := CalendarItem{
- comp_type: .vtodo
- todo: todo
- }
-
- cal.put(obj) or { panic(err) }
-
- // Test completion
- mut updated_todo := todo
- updated_todo.status = .completed
- updated_todo.completed = 1708074000
- updated_todo.percent = 100
-
- updated_obj := CalendarItem{
- comp_type: .vtodo
- todo: updated_todo
- }
-
- cal.put(updated_obj) or { panic(err) }
-
- // Verify update
- found := cal.get_by_uid('todo1@example.com') or { panic(err) }
- if t := found.todo {
- assert t.status == .completed
- assert t.completed? == 1708074000
- assert t.percent? == 100
- } else {
- assert false, 'Todo not found'
- }
-}
-
-fn test_create_journal() {
- mut cal := new('test_calendar')
-
- // Create a journal entry
- journal := Journal{
- CalendarComponent: CalendarComponent{
- uid: 'journal1@example.com'
- etag: '"1"'
- created: 1708070400
- modified: 1708070400
- summary: 'Project Notes'
- description: 'Today we discussed the new features...'
- categories: ['Work', 'Notes']
- }
- start_time: 1708070400 // 2024-02-16 09:00:00 UTC
- }
-
- obj := CalendarItem{
- comp_type: .vjournal
- journal: journal
- }
-
- cal.put(obj) or { panic(err) }
- assert cal.len() == 1
-
- // Test time range search
- tr := TimeRange{
- start: 1708070400 // 2024-02-16 09:00:00 UTC
- end: 1708074000 // 2024-02-16 10:00:00 UTC
- }
-
- results := cal.find_by_time(tr) or { panic(err) }
- assert results.len == 1
-}
-
-fn test_validation() {
- mut cal := new('test_calendar')
-
- // Test invalid component type
- invalid_type := CalendarItem{
- comp_type: .vevent // Using a valid type but with invalid data
- }
- if _ := cal.put(invalid_type) {
- assert false, 'Should reject invalid component type'
- }
-
- // Test missing required fields
- invalid_event := CalendarItem{
- comp_type: .vevent
- event: Event{}
- }
- if _ := cal.put(invalid_event) {
- assert false, 'Should reject event without required fields'
- }
-
- // Test too many attendees
- mut many_attendees := []Attendee{cap: 200}
- for i in 0 .. 200 {
- many_attendees << Attendee{
- email: 'user${i}@example.com'
- name: 'User ${i}'
- }
- }
-
- event_many_attendees := CalendarItem{
- comp_type: .vevent
- event: Event{
- CalendarComponent: CalendarComponent{
- uid: 'many@example.com'
- }
- start_time: 1708070400
- end_time: 1708074000
- attendees: many_attendees
- }
- }
- if _ := cal.put(event_many_attendees) {
- assert false, 'Should reject event with too many attendees'
- }
-}
-
-fn test_read_only() {
- mut cal := new('test_calendar')
- cal.read_only = true
-
- event := CalendarItem{
- comp_type: .vevent
- event: Event{
- CalendarComponent: CalendarComponent{
- uid: 'test@example.com'
- }
- start_time: 1708070400
- end_time: 1708074000
- }
- }
-
- // Test put
- if _ := cal.put(event) {
- assert false, 'Should reject put on read-only calendar'
- }
-
- // Test delete
- if _ := cal.delete('test@example.com') {
- assert false, 'Should reject delete on read-only calendar'
- }
-}
diff --git a/lib/servers/calendar/calbox/datetime.v b/lib/servers/calendar/calbox/datetime.v
deleted file mode 100644
index 9871a776..00000000
--- a/lib/servers/calendar/calbox/datetime.v
+++ /dev/null
@@ -1,104 +0,0 @@
-module calbox
-
-import time
-
-// Converts a timestamp to iCalendar UTC date-time format (YYYYMMDDTHHMMSSZ)
-pub fn format_datetime_utc(ts i64) string {
- t := time.unix(ts)
- return t.strftime('%Y%m%dT%H%M%SZ')
-}
-
-// Converts a timestamp to iCalendar date format (YYYYMMDD)
-pub fn format_date(ts i64) string {
- t := time.unix(ts)
- return t.strftime('%Y%m%d')
-}
-
-// Parses an iCalendar date-time string to timestamp
-pub fn parse_datetime(dt string) !i64 {
- if dt.len < 8 {
- return error('Invalid date-time format')
- }
-
- // Parse date part (YYYYMMDD)
- year := dt[0..4].int()
- month := dt[4..6].int()
- day := dt[6..8].int()
-
- mut hour := 0
- mut min := 0
- mut sec := 0
- mut is_utc := false
-
- // Parse time part if present (THHMMSS[Z])
- if dt.len > 8 {
- if dt[8] != `T` {
- return error('Invalid date-time format: missing T separator')
- }
- if dt.len < 15 {
- return error('Invalid date-time format: incomplete time')
- }
-
- hour = dt[9..11].int()
- min = dt[11..13].int()
- sec = dt[13..15].int()
-
- is_utc = dt.ends_with('Z')
- }
-
- // Create time.Time
- mut t := time.new(
- year: year
- month: month
- day: day
- hour: hour
- minute: min
- second: sec
- )
-
- // Convert to UTC if needed
- if !is_utc {
- // TODO: Handle local time conversion
- // For now assume UTC
- }
-
- return t.unix()
-}
-
-// Parses an iCalendar date string to timestamp
-pub fn parse_date(d string) !i64 {
- if d.len != 8 {
- return error('Invalid date format: must be YYYYMMDD')
- }
-
- year := d[0..4].int()
- month := d[4..6].int()
- day := d[6..8].int()
-
- t := time.new(
- year: year
- month: month
- day: day
- hour: 0
- minute: 0
- second: 0
- )
-
- return t.unix()
-}
-
-// Parses a date or date-time string
-pub fn parse_date_or_datetime(value string) !i64 {
- if value.contains('T') {
- return parse_datetime(value)!
- }
- return parse_date(value)!
-}
-
-// Formats a timestamp as either date or date-time based on has_time flag
-pub fn format_date_or_datetime(ts i64, has_time bool) string {
- if has_time {
- return format_datetime_utc(ts)
- }
- return format_date(ts)
-}
diff --git a/lib/servers/calendar/calbox/datetime_test.v b/lib/servers/calendar/calbox/datetime_test.v
deleted file mode 100644
index eb89c36c..00000000
--- a/lib/servers/calendar/calbox/datetime_test.v
+++ /dev/null
@@ -1,103 +0,0 @@
-module calbox
-
-fn test_format_datetime_utc() {
- // Test specific timestamp: 2024-02-16 10:00:00 UTC
- ts := i64(1708074000)
- formatted := format_datetime_utc(ts)
- assert formatted == '20240216T100000Z'
-
- // Test midnight
- midnight := i64(1708041600) // 2024-02-16 00:00:00 UTC
- midnight_formatted := format_datetime_utc(midnight)
- assert midnight_formatted == '20240216T000000Z'
-}
-
-fn test_format_date() {
- // Test specific date
- ts := i64(1708074000) // 2024-02-16 10:00:00 UTC
- formatted := format_date(ts)
- assert formatted == '20240216'
-
- // Time part should be ignored
- later := i64(1708117200) // 2024-02-16 22:00:00 UTC
- later_formatted := format_date(later)
- assert later_formatted == '20240216'
-}
-
-fn test_parse_datetime() {
- // Test UTC date-time
- ts := parse_datetime('20240216T100000Z')!
- assert ts == 1708074000
-
- // Test date-time without seconds
- no_seconds := parse_datetime('20240216T1000')!
- assert no_seconds == 1708074000
-
- // Test invalid formats
- if _ := parse_datetime('invalid') {
- assert false, 'Should reject invalid format'
- }
- if _ := parse_datetime('20240216') {
- assert false, 'Should reject date without time'
- }
- if _ := parse_datetime('20240216T') {
- assert false, 'Should reject incomplete time'
- }
-}
-
-fn test_parse_date() {
- // Test basic date
- ts := parse_date('20240216')!
- assert ts == 1708041600 // 2024-02-16 00:00:00 UTC
-
- // Test invalid formats
- if _ := parse_date('2024021') {
- assert false, 'Should reject too short date'
- }
- if _ := parse_date('202402166') {
- assert false, 'Should reject too long date'
- }
- if _ := parse_date('20240216T100000Z') {
- assert false, 'Should reject date-time format'
- }
-}
-
-fn test_parse_date_or_datetime() {
- // Test date format
- date_ts := parse_date_or_datetime('20240216')!
- assert date_ts == 1708041600 // 2024-02-16 00:00:00 UTC
-
- // Test date-time format
- datetime_ts := parse_date_or_datetime('20240216T100000Z')!
- assert datetime_ts == 1708074000 // 2024-02-16 10:00:00 UTC
-
- // Test invalid formats
- if _ := parse_date_or_datetime('invalid') {
- assert false, 'Should reject invalid format'
- }
-}
-
-fn test_format_date_or_datetime() {
- ts := i64(1708074000) // 2024-02-16 10:00:00 UTC
-
- // Test as date-time
- datetime := format_date_or_datetime(ts, true)
- assert datetime == '20240216T100000Z'
-
- // Test as date
- date := format_date_or_datetime(ts, false)
- assert date == '20240216'
-}
-
-fn test_roundtrip() {
- // Test date-time roundtrip
- original_ts := i64(1708074000)
- formatted := format_datetime_utc(original_ts)
- parsed_ts := parse_datetime(formatted)!
- assert parsed_ts == original_ts
-
- // Test date roundtrip
- date_formatted := format_date(original_ts)
- date_ts := parse_date(date_formatted)!
- assert date_ts == i64(1708041600) // Should be start of day
-}
diff --git a/lib/servers/calendar/calbox/duration.v b/lib/servers/calendar/calbox/duration.v
deleted file mode 100644
index cb795916..00000000
--- a/lib/servers/calendar/calbox/duration.v
+++ /dev/null
@@ -1,167 +0,0 @@
-module calbox
-
-// Represents a duration in seconds
-pub struct Duration {
-pub:
- seconds i64
-}
-
-// Parses an ISO 8601 duration string (e.g. PT1H30M)
-pub fn parse_duration(iso_duration string) !Duration {
- if iso_duration.len < 2 || !iso_duration.starts_with('P') {
- return error('Invalid duration format: must start with P')
- }
-
- mut seconds := i64(0)
- mut number_str := ''
- mut time_part := false
-
- for i := 1; i < iso_duration.len; i++ {
- c := iso_duration[i]
- match c {
- `T` {
- if time_part {
- return error('Invalid duration format: duplicate T')
- }
- time_part = true
- }
- `0`...`9` {
- number_str += c.ascii_str()
- }
- `Y` {
- if time_part {
- return error('Invalid duration format: Y in time part')
- }
- if number_str == '' {
- return error('Invalid duration format: missing number before Y')
- }
- years := number_str.i64()
- seconds += years * 365 * 24 * 60 * 60 // Approximate
- number_str = ''
- }
- `M` {
- if number_str == '' {
- return error('Invalid duration format: missing number before M')
- }
- if time_part {
- // Minutes
- minutes := number_str.i64()
- seconds += minutes * 60
- } else {
- // Months
- months := number_str.i64()
- seconds += months * 30 * 24 * 60 * 60 // Approximate
- }
- number_str = ''
- }
- `W` {
- if time_part {
- return error('Invalid duration format: W in time part')
- }
- if number_str == '' {
- return error('Invalid duration format: missing number before W')
- }
- weeks := number_str.i64()
- seconds += weeks * 7 * 24 * 60 * 60
- number_str = ''
- }
- `D` {
- if time_part {
- return error('Invalid duration format: D in time part')
- }
- if number_str == '' {
- return error('Invalid duration format: missing number before D')
- }
- days := number_str.i64()
- seconds += days * 24 * 60 * 60
- number_str = ''
- }
- `H` {
- if !time_part {
- return error('Invalid duration format: H in date part')
- }
- if number_str == '' {
- return error('Invalid duration format: missing number before H')
- }
- hours := number_str.i64()
- seconds += hours * 60 * 60
- number_str = ''
- }
- `S` {
- if !time_part {
- return error('Invalid duration format: S in date part')
- }
- if number_str == '' {
- return error('Invalid duration format: missing number before S')
- }
- seconds += number_str.i64()
- number_str = ''
- }
- else {
- return error('Invalid duration format: unknown character ${c}')
- }
- }
- }
-
- if number_str != '' {
- return error('Invalid duration format: number without unit')
- }
-
- return Duration{seconds}
-}
-
-// Formats the duration as an ISO 8601 duration string
-pub fn (d Duration) str() string {
- mut s := 'P'
- mut remaining := d.seconds
-
- // Years (approximate)
- years := remaining / (365 * 24 * 60 * 60)
- if years > 0 {
- s += '${years}Y'
- remaining = remaining % (365 * 24 * 60 * 60)
- }
-
- // Days
- days := remaining / (24 * 60 * 60)
- if days > 0 {
- s += '${days}D'
- remaining = remaining % (24 * 60 * 60)
- }
-
- // Time part (hours, minutes, seconds)
- if remaining > 0 {
- s += 'T'
-
- // Hours
- hours := remaining / (60 * 60)
- if hours > 0 {
- s += '${hours}H'
- remaining = remaining % (60 * 60)
- }
-
- // Minutes
- minutes := remaining / 60
- if minutes > 0 {
- s += '${minutes}M'
- remaining = remaining % 60
- }
-
- // Seconds
- if remaining > 0 {
- s += '${remaining}S'
- }
- }
-
- return s
-}
-
-// Adds the duration to a timestamp
-pub fn (d Duration) add_to(timestamp i64) i64 {
- return timestamp + d.seconds
-}
-
-// Subtracts the duration from a timestamp
-pub fn (d Duration) subtract_from(timestamp i64) i64 {
- return timestamp - d.seconds
-}
diff --git a/lib/servers/calendar/calbox/duration_test.v b/lib/servers/calendar/calbox/duration_test.v
deleted file mode 100644
index 8119338a..00000000
--- a/lib/servers/calendar/calbox/duration_test.v
+++ /dev/null
@@ -1,98 +0,0 @@
-module calbox
-
-fn test_parse_duration() {
- // Test simple durations
- assert parse_duration('PT1H')!.seconds == 3600
- assert parse_duration('PT30M')!.seconds == 1800
- assert parse_duration('PT15S')!.seconds == 15
-
- // Test combined durations
- assert parse_duration('PT1H30M')!.seconds == 5400
- assert parse_duration('PT1H30M15S')!.seconds == 5415
-
- // Test days
- assert parse_duration('P1D')!.seconds == 86400
- assert parse_duration('P1DT12H')!.seconds == 129600
-
- // Test weeks
- assert parse_duration('P2W')!.seconds == 1209600
-
- // Test years (approximate)
- assert parse_duration('P1Y')!.seconds == 31536000
-
- // Test zero duration
- assert parse_duration('PT0S')!.seconds == 0
-
- // Test invalid formats
- if _ := parse_duration('invalid') {
- assert false, 'Should reject invalid format'
- }
- if _ := parse_duration('P') {
- assert false, 'Should reject empty duration'
- }
- if _ := parse_duration('PT1H30') {
- assert false, 'Should reject number without unit'
- }
- if _ := parse_duration('PT1HM') {
- assert false, 'Should reject missing number before unit'
- }
- if _ := parse_duration('P1H') {
- assert false, 'Should reject time unit in date part'
- }
- if _ := parse_duration('PT1D') {
- assert false, 'Should reject date unit in time part'
- }
-}
-
-fn test_duration_string() {
- // Test simple durations
- assert parse_duration('PT1H')!.str() == 'PT1H'
- assert parse_duration('PT30M')!.str() == 'PT30M'
- assert parse_duration('PT15S')!.str() == 'PT15S'
-
- // Test combined durations
- assert parse_duration('PT1H30M')!.str() == 'PT1H30M'
- assert parse_duration('PT1H30M15S')!.str() == 'PT1H30M15S'
-
- // Test days
- assert parse_duration('P1D')!.str() == 'P1D'
- assert parse_duration('P1DT12H')!.str() == 'P1DT12H'
-
- // Test normalization
- d := parse_duration('PT90M')!
- assert d.str() == 'PT1H30M' // 90 minutes normalized to 1 hour 30 minutes
-
- // Test zero duration
- assert parse_duration('PT0S')!.str() == 'P'
-}
-
-fn test_duration_arithmetic() {
- // Base timestamp: 2024-02-16 10:00:00 UTC
- base_ts := i64(1708074000)
-
- // Test addition
- one_hour := parse_duration('PT1H')!
- assert one_hour.add_to(base_ts) == base_ts + 3600
-
- // Test subtraction
- assert one_hour.subtract_from(base_ts) == base_ts - 3600
-
- // Test complex duration
- complex := parse_duration('P1DT2H30M')!
- expected := base_ts + (24 * 3600) + (2 * 3600) + (30 * 60)
- assert complex.add_to(base_ts) == expected
-}
-
-fn test_duration_edge_cases() {
- // Test very large durations
- large := parse_duration('P100Y')!
- assert large.seconds == i64(100 * 365 * 24 * 60 * 60)
-
- // Test combined date and time
- mixed := parse_duration('P1Y2DT3H4M5S')!
- assert mixed.str() == 'P1Y2DT3H4M5S'
-
- // Test months (approximate)
- with_months := parse_duration('P2M')!
- assert with_months.seconds == i64(2 * 30 * 24 * 60 * 60)
-}
diff --git a/lib/servers/calendar/calbox/event.v b/lib/servers/calendar/calbox/event.v
deleted file mode 100644
index de821f2c..00000000
--- a/lib/servers/calendar/calbox/event.v
+++ /dev/null
@@ -1,105 +0,0 @@
-module calbox
-
-// Represents an event
-@[heap]
-pub struct Event {
- CalendarComponent
-pub mut:
- start_time i64
- end_time ?i64 // Either end_time or duration must be set
- duration ?string // ISO 8601 duration format
- rrule ?RecurrenceRule
- rdate []i64 // Additional recurrence dates
- exdate []i64 // Dates to exclude
- transp EventTransp
- attendees []Attendee
- organizer ?Attendee
-}
-
-// Event transparency (busy time)
-pub enum EventTransp {
- opaque // Blocks time (shows as busy)
- transparent // Does not block time (shows as free)
-}
-
-// String representation of event transparency
-pub fn (t EventTransp) str() string {
- return match t {
- .opaque { 'OPAQUE' }
- .transparent { 'TRANSPARENT' }
- }
-}
-
-// Parse event transparency from string
-pub fn parse_event_transp(s string) !EventTransp {
- return match s {
- 'OPAQUE' { EventTransp.opaque }
- 'TRANSPARENT' { EventTransp.transparent }
- else { error('Invalid event transparency: ${s}') }
- }
-}
-
-// Checks if an event overlaps with a time range
-fn (event Event) overlaps(tr TimeRange) bool {
- // Get end time from either end_time or duration
- mut end_ts := event.end_time or {
- // TODO: Add duration parsing to get actual end time
- event.start_time + 3600 // Default 1 hour if no end/duration
- }
-
- // Check basic overlap
- if is_in_range(event.start_time, tr) || is_in_range(end_ts, tr) {
- return true
- }
-
- // Check recurrences if any
- if rule := event.rrule {
- // TODO: Implement recurrence expansion
- // For now just check if the rule's until date (if any) is after range start
- if until := rule.until {
- return until >= tr.start
- }
- return true // Infinite recurrence overlaps everything
- }
-
- return false
-}
-
-// Gets the effective end time of an event
-pub fn (event Event) get_effective_end_time() !i64 {
- if end := event.end_time {
- return end
- }
- if dur_str := event.duration {
- duration := parse_duration(dur_str)!
- return duration.add_to(event.start_time)
- }
- // Default 1 hour duration
- return event.start_time + 3600
-}
-
-// Gets all instances of an event that overlap with a time range
-pub fn (event Event) get_instances(tr TimeRange) ![]EventInstance {
- // For non-recurring events, just check if it overlaps
- if event.rrule == none && event.rdate.len == 0 {
- end_time := event.get_effective_end_time()!
- if event.start_time < tr.end && end_time > tr.start {
- return [
- EventInstance{
- original_event: event
- start_time: event.start_time
- end_time: end_time
- recurrence_id: event.start_time
- is_override: false
- },
- ]
- }
- return []
- }
-
- // Expand recurring event
- if instances := expand_recurring_event(event, tr) {
- return instances
- }
- return []
-}
diff --git a/lib/servers/calendar/calbox/event_instance.v b/lib/servers/calendar/calbox/event_instance.v
deleted file mode 100644
index e3c56020..00000000
--- a/lib/servers/calendar/calbox/event_instance.v
+++ /dev/null
@@ -1,11 +0,0 @@
-module calbox
-
-// Represents a single instance of a recurring event
-pub struct EventInstance {
-pub:
- original_event Event // Reference to original event
- start_time i64 // Start time of this instance
- end_time i64 // End time of this instance
- recurrence_id i64 // RECURRENCE-ID for this instance
- is_override bool // Whether this is an overridden instance
-}
diff --git a/lib/servers/calendar/calbox/journal.v b/lib/servers/calendar/calbox/journal.v
deleted file mode 100644
index 0eedddde..00000000
--- a/lib/servers/calendar/calbox/journal.v
+++ /dev/null
@@ -1,11 +0,0 @@
-module calbox
-
-// Represents a journal entry
-@[heap]
-pub struct Journal {
- CalendarComponent
-pub mut:
- start_time i64 // Date of the journal entry
- attendees []Attendee
- organizer ?Attendee
-}
diff --git a/lib/servers/calendar/calbox/recurrence.v b/lib/servers/calendar/calbox/recurrence.v
deleted file mode 100644
index ffff9c51..00000000
--- a/lib/servers/calendar/calbox/recurrence.v
+++ /dev/null
@@ -1,124 +0,0 @@
-module calbox
-
-// Gets the next occurrence after a given timestamp based on a recurrence rule
-fn (rule RecurrenceRule) next_occurrence(base_time i64, after i64) ?i64 {
- if rule.until != none && after >= rule.until? {
- return none
- }
-
- // Calculate interval in seconds based on frequency
- mut interval_seconds := i64(0)
- match rule.frequency {
- .secondly { interval_seconds = rule.interval }
- .minutely { interval_seconds = rule.interval * 60 }
- .hourly { interval_seconds = rule.interval * 3600 }
- .daily { interval_seconds = rule.interval * 86400 }
- .weekly { interval_seconds = rule.interval * 7 * 86400 }
- .monthly { interval_seconds = rule.interval * 30 * 86400 } // Approximate
- .yearly { interval_seconds = rule.interval * 365 * 86400 } // Approximate
- }
-
- // Calculate number of intervals between base_time and after
- mut intervals := i64(0)
- if after > base_time {
- intervals = ((after - base_time) / interval_seconds) + 1
- }
-
- // Calculate next occurrence
- mut next := base_time + (intervals * interval_seconds)
-
- // TODO: Apply BYDAY, BYMONTHDAY etc. rules
- if rule.until != none && next > rule.until? {
- return none
- }
- return next
-}
-
-// Expands a recurring event into individual instances within a time range
-pub fn expand_recurring_event(event Event, tr TimeRange) ?[]EventInstance {
- mut instances := []EventInstance{}
-
- // Get event duration
- mut duration := i64(0)
- if end := event.end_time {
- duration = end - event.start_time
- } else if dur_str := event.duration {
- duration = parse_duration(dur_str) or { return none }.seconds
- } else {
- duration = 3600 // Default 1 hour
- }
-
- // Handle recurrence rule if any
- if rule := event.rrule {
- mut current := event.start_time
- mut total_instances := 0
-
- // Generate instances until we hit count limit or range end
- for {
- // Add instance if in range and not excluded
- if current >= tr.start && current < tr.end && current !in event.exdate {
- instances << EventInstance{
- original_event: event
- start_time: current
- end_time: current + duration
- recurrence_id: current
- is_override: false
- }
- }
-
- total_instances++
-
- // Check count limit if specified
- if count := rule.count {
- if total_instances >= count {
- break
- }
- }
-
- // Calculate next occurrence
- mut interval_seconds := rule.interval * match rule.frequency {
- .secondly { 1 }
- .minutely { 60 }
- .hourly { 3600 }
- .daily { 86400 }
- .weekly { 7 * 86400 }
- .monthly { 30 * 86400 } // Approximate
- .yearly { 365 * 86400 } // Approximate
- }
- current += interval_seconds
-
- // Break if we hit until limit
- if rule.until != none && current > rule.until? {
- break
- }
-
- // Break if we're past the range and no count limit
- if current >= tr.end && rule.count == none {
- break
- }
-
- // Break if we're past the range and have enough instances
- if current >= tr.end && total_instances >= (rule.count or { 0 }) {
- break
- }
- }
- }
-
- // Add any additional dates
- for rdate in event.rdate {
- if rdate >= tr.start && rdate < tr.end && rdate !in event.exdate {
- instances << EventInstance{
- original_event: event
- start_time: rdate
- end_time: rdate + duration
- recurrence_id: rdate
- is_override: false
- }
- }
- }
-
- // Sort instances by start time
- instances.sort(a.start_time < b.start_time)
-
- return instances
-}
diff --git a/lib/servers/calendar/calbox/recurrence_rule.v b/lib/servers/calendar/calbox/recurrence_rule.v
deleted file mode 100644
index 258ac7bd..00000000
--- a/lib/servers/calendar/calbox/recurrence_rule.v
+++ /dev/null
@@ -1,59 +0,0 @@
-module calbox
-
-// Represents a recurrence rule
-@[heap]
-pub struct RecurrenceRule {
-pub mut:
- frequency RecurrenceFrequency
- interval int // How often the recurrence rule repeats
- count ?int // Number of occurrences
- until ?i64 // End date timestamp
- by_second []int
- by_minute []int
- by_hour []int
- by_day []string // MO, TU, WE, TH, FR, SA, SU with optional +/-prefix
- by_monthday []int
- by_yearday []int
- by_weekno []int
- by_month []int
- by_setpos []int
- week_start string // MO, TU, WE, TH, FR, SA, SU
-}
-
-// Recurrence frequency types
-pub enum RecurrenceFrequency {
- secondly
- minutely
- hourly
- daily
- weekly
- monthly
- yearly
-}
-
-// String representation of recurrence frequency
-pub fn (f RecurrenceFrequency) str() string {
- return match f {
- .secondly { 'SECONDLY' }
- .minutely { 'MINUTELY' }
- .hourly { 'HOURLY' }
- .daily { 'DAILY' }
- .weekly { 'WEEKLY' }
- .monthly { 'MONTHLY' }
- .yearly { 'YEARLY' }
- }
-}
-
-// Parse recurrence frequency from string
-pub fn parse_recurrence_frequency(s string) !RecurrenceFrequency {
- return match s {
- 'SECONDLY' { RecurrenceFrequency.secondly }
- 'MINUTELY' { RecurrenceFrequency.minutely }
- 'HOURLY' { RecurrenceFrequency.hourly }
- 'DAILY' { RecurrenceFrequency.daily }
- 'WEEKLY' { RecurrenceFrequency.weekly }
- 'MONTHLY' { RecurrenceFrequency.monthly }
- 'YEARLY' { RecurrenceFrequency.yearly }
- else { error('Invalid recurrence frequency: ${s}') }
- }
-}
diff --git a/lib/servers/calendar/calbox/recurrence_test.v b/lib/servers/calendar/calbox/recurrence_test.v
deleted file mode 100644
index 11957961..00000000
--- a/lib/servers/calendar/calbox/recurrence_test.v
+++ /dev/null
@@ -1,190 +0,0 @@
-module calbox
-
-fn test_simple_recurrence() {
- // Create a daily recurring event
- event := Event{
- CalendarComponent: CalendarComponent{
- uid: 'daily@example.com'
- }
- start_time: 1708074000 // 2024-02-16 10:00:00 UTC
- duration: 'PT1H'
- rrule: RecurrenceRule{
- frequency: .daily
- interval: 1
- count: 3
- }
- }
-
- // Search for instances over 3 days
- tr := TimeRange{
- start: 1708074000 // 2024-02-16 10:00:00 UTC
- end: 1708333200 // 2024-02-19 10:00:00 UTC
- }
-
- instances := event.get_instances(tr)!
- assert instances.len == 3
-
- // Verify instance times
- assert instances[0].start_time == 1708074000 // Feb 16 10:00
- assert instances[1].start_time == 1708160400 // Feb 17 10:00
- assert instances[2].start_time == 1708246800 // Feb 18 10:00
-
- // Verify duration
- for instance in instances {
- duration := instance.end_time - instance.start_time
- assert duration == 3600 // 1 hour
- }
-}
-
-fn test_recurrence_with_until() {
- // Create event recurring daily until a specific time
- event := Event{
- CalendarComponent: CalendarComponent{
- uid: 'until@example.com'
- }
- start_time: 1708074000 // 2024-02-16 10:00:00 UTC
- duration: 'PT1H'
- rrule: RecurrenceRule{
- frequency: .daily
- interval: 1
- until: 1708246800 // 2024-02-18 10:00:00 UTC
- }
- }
-
- // Search beyond the until date
- tr := TimeRange{
- start: 1708074000 // 2024-02-16 10:00:00 UTC
- end: 1708333200 // 2024-02-19 10:00:00 UTC
- }
-
- instances := event.get_instances(tr)!
- assert instances.len == 3 // Should include the until date
-}
-
-fn test_recurrence_with_interval() {
- // Create event recurring every 2 days
- event := Event{
- CalendarComponent: CalendarComponent{
- uid: 'interval@example.com'
- }
- start_time: 1708074000 // 2024-02-16 10:00:00 UTC
- duration: 'PT1H'
- rrule: RecurrenceRule{
- frequency: .daily
- interval: 2
- count: 3
- }
- }
-
- // Search for a week
- tr := TimeRange{
- start: 1708074000 // 2024-02-16 10:00:00 UTC
- end: 1708592400 // 2024-02-22 10:00:00 UTC
- }
-
- instances := event.get_instances(tr)!
- assert instances.len == 3
-
- // Verify instance times (every 2 days)
- assert instances[0].start_time == 1708074000 // Feb 16 10:00
- assert instances[1].start_time == 1708246800 // Feb 18 10:00
- assert instances[2].start_time == 1708419600 // Feb 20 10:00
-}
-
-fn test_recurrence_with_exclusions() {
- // Create daily event with exclusions
- event := Event{
- CalendarComponent: CalendarComponent{
- uid: 'exclude@example.com'
- }
- start_time: 1708074000 // 2024-02-16 10:00:00 UTC
- duration: 'PT1H'
- rrule: RecurrenceRule{
- frequency: .daily
- interval: 1
- count: 5
- }
- exdate: [i64(1708246800)] // Exclude Feb 18 10:00
- }
-
- // Search for a week
- tr := TimeRange{
- start: 1708074000 // 2024-02-16 10:00:00 UTC
- end: 1708592400 // 2024-02-22 10:00:00 UTC
- }
-
- instances := event.get_instances(tr)!
- assert instances.len == 4 // 5 occurrences - 1 exclusion
-
- // Verify excluded date is not present
- for instance in instances {
- assert instance.start_time != 1708246800
- }
-}
-
-fn test_recurrence_with_additional_dates() {
- // Create event with additional dates
- event := Event{
- CalendarComponent: CalendarComponent{
- uid: 'rdate@example.com'
- }
- start_time: 1708074000 // 2024-02-16 10:00:00 UTC
- duration: 'PT1H'
- rrule: RecurrenceRule{
- frequency: .daily
- interval: 1
- count: 2
- }
- rdate: [
- i64(1708333200), // Feb 19 10:00
- i64(1708419600), // Feb 20 10:00
- ]
- }
-
- // Search for a week
- tr := TimeRange{
- start: 1708074000 // 2024-02-16 10:00:00 UTC
- end: 1708592400 // 2024-02-22 10:00:00 UTC
- }
-
- instances := event.get_instances(tr)!
- assert instances.len == 4 // 2 regular + 2 additional
-
- // Verify additional dates are included
- mut found_additional := false
- for instance in instances {
- if instance.start_time == 1708333200 || instance.start_time == 1708419600 {
- found_additional = true
- }
- }
- assert found_additional
-}
-
-fn test_non_recurring_event() {
- // Create single event
- event := Event{
- CalendarComponent: CalendarComponent{
- uid: 'single@example.com'
- }
- start_time: 1708074000 // 2024-02-16 10:00:00 UTC
- end_time: 1708077600 // 2024-02-16 11:00:00 UTC
- }
-
- // Search including event time
- tr := TimeRange{
- start: 1708070400 // 2024-02-16 09:00:00 UTC
- end: 1708084800 // 2024-02-16 12:00:00 UTC
- }
-
- instances := event.get_instances(tr)!
- assert instances.len == 1
-
- // Search outside event time
- tr_outside := TimeRange{
- start: 1708333200 // 2024-02-19 10:00:00 UTC
- end: 1708336800 // 2024-02-19 11:00:00 UTC
- }
-
- outside_instances := event.get_instances(tr_outside)!
- assert outside_instances.len == 0
-}
diff --git a/lib/servers/calendar/calbox/timerange.v b/lib/servers/calendar/calbox/timerange.v
deleted file mode 100644
index c377aed2..00000000
--- a/lib/servers/calendar/calbox/timerange.v
+++ /dev/null
@@ -1,13 +0,0 @@
-module calbox
-
-@[params]
-pub struct TimeRange {
-pub mut:
- start i64 // UTC timestamp (epoch)
- end i64 // UTC timestamp
-}
-
-// Checks if a timestamp falls within a time range
-fn is_in_range(ts i64, tr TimeRange) bool {
- return ts >= tr.start && ts < tr.end
-}
diff --git a/lib/servers/calendar/calbox/todo.v b/lib/servers/calendar/calbox/todo.v
deleted file mode 100644
index c29a99cc..00000000
--- a/lib/servers/calendar/calbox/todo.v
+++ /dev/null
@@ -1,39 +0,0 @@
-module calbox
-
-// Represents a todo/task
-@[heap]
-pub struct Todo {
- CalendarComponent
-pub mut:
- start_time ?i64 // Optional start time
- due_time ?i64 // When the todo is due
- duration ?string // Estimated duration
- completed ?i64 // When the todo was completed
- percent ?int // Percent complete (0-100)
- rrule ?RecurrenceRule
- attendees []Attendee
- organizer ?Attendee
-}
-
-// Checks if a todo overlaps with a time range
-fn (todo Todo) overlaps(tr TimeRange) bool {
- if start := todo.start_time {
- if is_in_range(start, tr) {
- return true
- }
- }
-
- if due := todo.due_time {
- if is_in_range(due, tr) {
- return true
- }
- }
-
- if completed := todo.completed {
- if is_in_range(completed, tr) {
- return true
- }
- }
-
- return false
-}
diff --git a/lib/servers/calendar/caldav/acl.v b/lib/servers/calendar/caldav/acl.v
deleted file mode 100644
index aaff7fac..00000000
--- a/lib/servers/calendar/caldav/acl.v
+++ /dev/null
@@ -1,119 +0,0 @@
-module caldav
-
-// CalDAV privileges
-pub const read_free_busy = 'read-free-busy' // Allows reading free/busy information
-
-pub const read = 'read' // Allows reading calendar data
-
-pub const write = 'write' // Allows writing calendar data
-
-pub const write_content = 'write-content' // Allows modifying calendar object resources
-
-pub const write_props = 'write-props' // Allows modifying collection properties
-
-pub const bind = 'bind' // Allows creating new calendar object resources
-
-pub const unbind = 'unbind' // Allows deleting calendar object resources
-
-pub const admin = 'admin' // Allows administrative operations
-
-// Principal represents a user or group
-pub struct Principal {
-pub mut:
- id string
- name string
- email string
- calendar_home_set string
-}
-
-// ACLEntry represents an access control entry
-pub struct ACLEntry {
-pub mut:
- principal Principal
- privileges []string
- inherited bool
- protected bool
-}
-
-// ACL represents an access control list
-pub struct ACL {
-pub mut:
- entries []ACLEntry
-}
-
-// Creates a new ACL
-pub fn new_acl() ACL {
- return ACL{
- entries: []ACLEntry{}
- }
-}
-
-// Adds an ACL entry
-pub fn (mut acl ACL) add_entry(principal Principal, privileges []string, inherited bool, protected bool) {
- acl.entries << ACLEntry{
- principal: principal
- privileges: privileges
- inherited: inherited
- protected: protected
- }
-}
-
-// Checks if a principal has a privilege
-pub fn (acl ACL) has_privilege(principal Principal, privilege string) bool {
- for entry in acl.entries {
- if entry.principal.id == principal.id {
- return privilege in entry.privileges
- }
- }
- return false
-}
-
-// Gets all privileges for a principal
-pub fn (acl ACL) get_privileges(principal Principal) []string {
- for entry in acl.entries {
- if entry.principal.id == principal.id {
- return entry.privileges
- }
- }
- return []string{}
-}
-
-// Removes an ACL entry
-pub fn (mut acl ACL) remove_entry(principal Principal) {
- for i, entry in acl.entries {
- if entry.principal.id == principal.id {
- acl.entries.delete(i)
- break
- }
- }
-}
-
-// Checks if a principal has read access
-pub fn (acl ACL) can_read(principal Principal) bool {
- return acl.has_privilege(principal, read) || acl.has_privilege(principal, admin)
-}
-
-// Checks if a principal has write access
-pub fn (acl ACL) can_write(principal Principal) bool {
- return acl.has_privilege(principal, write) || acl.has_privilege(principal, admin)
-}
-
-// Checks if a principal has free/busy read access
-pub fn (acl ACL) can_read_freebusy(principal Principal) bool {
- return acl.has_privilege(principal, read_free_busy) || acl.can_read(principal)
-}
-
-// Checks if a principal can bind (create) resources
-pub fn (acl ACL) can_bind(principal Principal) bool {
- return acl.has_privilege(principal, bind) || acl.has_privilege(principal, write)
-}
-
-// Checks if a principal can unbind (delete) resources
-pub fn (acl ACL) can_unbind(principal Principal) bool {
- return acl.has_privilege(principal, unbind) || acl.has_privilege(principal, write)
-}
-
-// Checks if a principal has admin access
-pub fn (acl ACL) is_admin(principal Principal) bool {
- return acl.has_privilege(principal, admin)
-}
diff --git a/lib/servers/calendar/caldav/collection.v b/lib/servers/calendar/caldav/collection.v
deleted file mode 100644
index 6d3e6c61..00000000
--- a/lib/servers/calendar/caldav/collection.v
+++ /dev/null
@@ -1,155 +0,0 @@
-module caldav
-
-import calendar.calbox
-
-// Represents a CalDAV collection
-pub struct Collection {
-pub mut:
- path string
- cal &calbox.CalBox
- props map[string]string
- acl ACL
- parent ?&Collection
- children map[string]&Collection
- is_calendar bool
-}
-
-// Creates a new collection
-pub fn new_collection(path string, is_calendar bool) &Collection {
- mut col := &Collection{
- path: path
- props: map[string]string{}
- acl: new_acl()
- children: map[string]&Collection{}
- is_calendar: is_calendar
- }
-
- if is_calendar {
- col.cal = calbox.new(path.all_after_last('/'))
- }
-
- return col
-}
-
-// Gets a child collection by name
-pub fn (c Collection) get_child(name string) ?&Collection {
- return c.children[name]
-}
-
-// Adds a child collection
-pub fn (mut c Collection) add_child(name string, child &Collection) {
- c.children[name] = child
- child.parent = c
-}
-
-// Removes a child collection
-pub fn (mut c Collection) remove_child(name string) {
- c.children.delete(name)
-}
-
-// Gets all child collections
-pub fn (c Collection) list_children() []&Collection {
- mut children := []&Collection{}
- for _, child in c.children {
- children << child
- }
- return children
-}
-
-// Gets all calendar collections
-pub fn (c Collection) list_calendars() []&Collection {
- mut calendars := []&Collection{}
- for _, child in c.children {
- if child.is_calendar {
- calendars << child
- }
- calendars << child.list_calendars()
- }
- return calendars
-}
-
-// Gets all calendar collections for a principal
-pub fn (c Collection) list_principal_calendars(principal Principal) []&Collection {
- mut calendars := []&Collection{}
- for cal in c.list_calendars() {
- if cal.acl.can_read(principal) {
- calendars << cal
- }
- }
- return calendars
-}
-
-// Gets a collection by path
-pub fn (c Collection) find_by_path(path string) ?&Collection {
- if c.path == path {
- return c
- }
-
- parts := path.trim_left('/').split('/')
- mut current := &c
-
- for part in parts {
- if child := current.get_child(part) {
- current = child
- } else {
- return none
- }
- }
-
- return current
-}
-
-// Gets a calendar object by href
-pub fn (c Collection) get_object_by_href(href string) ?calbox.CalendarObject {
- if !c.is_calendar {
- return none
- }
-
- uid := href.all_after_last('/')
- return c.cal.get_by_uid(uid)
-}
-
-// Gets all calendar objects
-pub fn (c Collection) list_objects() []calbox.CalendarObject {
- if !c.is_calendar {
- return []calbox.CalendarObject{}
- }
-
- return c.cal.list() or { []calbox.CalendarObject{} }
-}
-
-// Gets all calendar objects matching a filter
-pub fn (c Collection) find_objects(filter CalendarQueryFilter) []calbox.CalendarObject {
- if !c.is_calendar {
- return []calbox.CalendarObject{}
- }
-
- return c.cal.find_by_filter(filter) or { []calbox.CalendarObject{} }
-}
-
-// Gets free/busy information
-pub fn (c Collection) get_freebusy(tr calbox.TimeRange) []calbox.TimeRange {
- if !c.is_calendar {
- return []calbox.TimeRange{}
- }
-
- return c.cal.get_freebusy(tr) or { []calbox.TimeRange{} }
-}
-
-// Adds/updates a calendar object
-pub fn (mut c Collection) put_object(obj calbox.CalendarObject) ! {
- if !c.is_calendar {
- return error('Not a calendar collection')
- }
-
- c.cal.put(obj)!
-}
-
-// Deletes a calendar object
-pub fn (mut c Collection) delete_object(uid string) ! {
- if !c.is_calendar {
- return error('Not a calendar collection')
- }
-
- c.cal.delete(uid)!
-}
diff --git a/lib/servers/calendar/caldav/errors.v b/lib/servers/calendar/caldav/errors.v
deleted file mode 100644
index 1675879e..00000000
--- a/lib/servers/calendar/caldav/errors.v
+++ /dev/null
@@ -1,126 +0,0 @@
-module caldav
-
-// Error codes
-pub const err_not_found = 404
-pub const err_forbidden = 403
-pub const err_conflict = 409
-pub const err_precondition_failed = 412
-pub const err_insufficient_storage = 507
-
-// Error types
-pub const err_calendar_not_found = 'Calendar collection not found'
-pub const err_resource_not_found = 'Calendar object resource not found'
-pub const err_calendar_exists = 'Calendar collection already exists'
-pub const err_resource_exists = 'Calendar object resource already exists'
-pub const err_invalid_calendar = 'Invalid calendar collection'
-pub const err_invalid_resource = 'Invalid calendar object resource'
-pub const err_uid_conflict = 'UID already in use'
-pub const err_no_privilege = 'Insufficient privileges'
-pub const err_storage_full = 'Insufficient storage space'
-
-// Precondition errors
-pub const err_supported_calendar_data = 'Unsupported calendar data format'
-pub const err_valid_calendar_data = 'Invalid calendar data'
-pub const err_valid_calendar_object = 'Invalid calendar object'
-pub const err_supported_component = 'Unsupported calendar component'
-pub const err_calendar_collection_location = 'Invalid calendar collection location'
-pub const err_resource_must_be_null = 'Resource already exists'
-pub const err_valid_calendar_timezone = 'Invalid calendar timezone'
-
-// CalDAV error with code and message
-pub struct CalDAVError {
-pub:
- code int
- message string
- href string // Optional resource href for errors like UID conflicts
-}
-
-// Creates a new CalDAV error
-pub fn new_error(code int, message string) CalDAVError {
- return CalDAVError{
- code: code
- message: message
- }
-}
-
-// Creates a new CalDAV error with href
-pub fn new_error_with_href(code int, message string, href string) CalDAVError {
- return CalDAVError{
- code: code
- message: message
- href: href
- }
-}
-
-// Common error constructors
-
-// Resource not found error
-pub fn err_not_found_error(message string) CalDAVError {
- return new_error(err_not_found, message)
-}
-
-// Permission denied error
-pub fn err_forbidden_error(message string) CalDAVError {
- return new_error(err_forbidden, message)
-}
-
-// Resource conflict error
-pub fn err_conflict_error(message string) CalDAVError {
- return new_error(err_conflict, message)
-}
-
-// Precondition failed error
-pub fn err_precondition_error(message string) CalDAVError {
- return new_error(err_precondition_failed, message)
-}
-
-// Storage full error
-pub fn err_storage_error(message string) CalDAVError {
- return new_error(err_insufficient_storage, message)
-}
-
-// UID conflict error with href
-pub fn err_uid_conflict_error(href string) CalDAVError {
- return new_error_with_href(err_conflict, err_uid_conflict, href)
-}
-
-// Generates XML error response
-pub fn (err CalDAVError) to_xml() string {
- mut xml := '\n'
- xml += '\n'
-
- match err.code {
- err_forbidden {
- xml += ' \n'
- xml += ' \n'
- xml += ' ${err.message}\n'
- xml += ' \n'
- xml += ' \n'
- }
- err_conflict {
- if err.message == err_uid_conflict && err.href != '' {
- xml += ' ${err.href}\n'
- } else {
- xml += ' \n'
- }
- }
- err_precondition_failed {
- xml += ' \n'
- xml += ' \n'
- xml += ' \n'
- xml += ' \n'
- xml += ' \n'
- xml += ' \n'
- xml += ' \n'
- xml += ' \n'
- xml += ' \n'
- xml += ' \n'
- }
- else {
- xml += ' \n'
- }
- }
-
- xml += ''
- return xml
-}
diff --git a/lib/servers/calendar/caldav/ical.v b/lib/servers/calendar/caldav/ical.v
deleted file mode 100644
index f02cf698..00000000
--- a/lib/servers/calendar/caldav/ical.v
+++ /dev/null
@@ -1,584 +0,0 @@
-module caldav
-
-import calendar.calbox
-import time
-
-// Formats a timestamp as an iCalendar date-time string
-fn format_datetime(ts i64) string {
- return calbox.format_datetime_utc(ts)
-}
-
-// Formats a date-time property with optional parameters
-fn format_datetime_property(name string, params map[string]string, ts i64) string {
- return format_property(name, params, calbox.format_datetime_utc(ts))
-}
-
-// Formats a date property with optional parameters
-fn format_date_property(name string, params map[string]string, ts i64) string {
- return format_property(name, params, calbox.format_date(ts))
-}
-
-// Formats a date or date-time property based on has_time flag
-fn format_date_or_datetime_property(name string, params map[string]string, ts i64, has_time bool) string {
- return format_property(name, params, calbox.format_date_or_datetime(ts, has_time))
-}
-
-// Splits a line into property name, parameters, and value
-fn parse_property(line string) !(string, map[string]string, string) {
- // Find the colon that separates name+params from value
- value_start := line.index(':') or { return error('Invalid property format: missing colon') }
-
- // Split into name+params and value
- name_params := line[..value_start].trim_space()
- value := line[value_start + 1..].trim_space()
-
- // Split name and parameters
- parts := name_params.split(';')
- name := parts[0]
-
- // Parse parameters
- mut params := map[string]string{}
- for i := 1; i < parts.len; i++ {
- param_parts := parts[i].split('=')
- if param_parts.len == 2 {
- params[param_parts[0]] = param_parts[1]
- }
- }
-
- return name, params, value
-}
-
-// Parses an iCalendar content line
-fn parse_content_line(line string) !string {
- // Handle line unfolding (lines starting with space/tab are continuations)
- if line.starts_with(' ') || line.starts_with('\t') {
- return line[1..]
- }
- return line
-}
-
-// Parses an attendee property value
-fn parse_attendee(value string, params map[string]string) !calbox.Attendee {
- mut attendee := calbox.Attendee{
- email: value.replace('mailto:', '')
- }
-
- if cn := params['CN'] {
- attendee.name = cn
- }
- if role := params['ROLE'] {
- attendee.role = calbox.parse_attendee_role(role)!
- }
- if partstat := params['PARTSTAT'] {
- attendee.partstat = calbox.parse_attendee_partstat(partstat)!
- }
- if rsvp := params['RSVP'] {
- attendee.rsvp = rsvp == 'TRUE'
- }
-
- return attendee
-}
-
-// Parses a recurrence rule
-fn parse_rrule(value string) !calbox.RecurrenceRule {
- mut rule := calbox.RecurrenceRule{
- interval: 1 // Default interval
- }
-
- parts := value.split(';')
- for part in parts {
- name_value := part.split('=')
- if name_value.len != 2 {
- continue
- }
-
- name := name_value[0]
- val := name_value[1]
-
- match name {
- 'FREQ' { rule.frequency = calbox.parse_recurrence_frequency(val)! }
- 'INTERVAL' { rule.interval = val.int() }
- 'COUNT' { rule.count = val.int() }
- 'UNTIL' { rule.until = calbox.parse_datetime(val)! }
- 'BYDAY' { rule.by_day = val.split(',') }
- 'BYMONTH' { rule.by_month = val.split(',').map(it.int()) }
- 'BYMONTHDAY' { rule.by_monthday = val.split(',').map(it.int()) }
- 'WKST' { rule.week_start = val }
- else {}
- }
- }
-
- return rule
-}
-
-// Parses an alarm component
-fn parse_alarm(lines []string) !calbox.Alarm {
- mut alarm := calbox.Alarm{}
- for i := 0; i < lines.len; i++ {
- line := lines[i]
- if line == 'END:VALARM' {
- break
- }
-
- name, params, value := parse_property(line)!
- match name {
- 'ACTION' { alarm.action = calbox.parse_alarm_action(value)! }
- 'TRIGGER' { alarm.trigger = value }
- 'DESCRIPTION' { alarm.description = value }
- 'SUMMARY' { alarm.summary = value }
- 'ATTENDEE' { alarm.attendees << parse_attendee(value, params)! }
- 'ATTACH' { alarm.attach << value }
- else {}
- }
- }
-
- return alarm
-}
-
-// Parses common component properties
-fn parse_component(lines []string, mut comp calbox.CalendarComponent) ! {
- for line in lines {
- if line.starts_with('BEGIN:') || line.starts_with('END:') {
- continue
- }
-
- name, params, value := parse_property(line)!
- match name {
- 'UID' {
- comp.uid = value
- }
- 'DTSTAMP' {
- comp.created = calbox.parse_datetime(value)!
- }
- 'LAST-MODIFIED' {
- comp.modified = calbox.parse_datetime(value)!
- }
- 'SUMMARY' {
- comp.summary = value
- }
- 'DESCRIPTION' {
- comp.description = value
- }
- 'CATEGORIES' {
- comp.categories = value.split(',')
- }
- 'STATUS' {
- comp.status = calbox.parse_component_status(value)!
- }
- 'CLASS' {
- comp.class = calbox.parse_component_class(value)!
- }
- 'URL' {
- comp.url = value
- }
- 'LOCATION' {
- comp.location = value
- }
- 'GEO' {
- parts := value.split(';')
- if parts.len == 2 {
- comp.geo = calbox.GeoLocation{
- latitude: parts[0].f64()
- longitude: parts[1].f64()
- }
- }
- }
- else {}
- }
- }
-}
-
-// Parses an iCalendar string into a calendar object
-pub fn from_ical(ical string) !calbox.CalendarObject {
- lines := ical.split_into_lines().map(parse_content_line)!
-
- mut obj := calbox.CalendarObject{}
- mut in_component := false
- mut component_lines := []string{}
-
- for line in lines {
- if line.starts_with('BEGIN:V') {
- if line == 'BEGIN:VCALENDAR' {
- continue
- }
- in_component = true
- obj.comp_type = line.replace('BEGIN:', '')
- continue
- }
-
- if line.starts_with('END:V') {
- if line == 'END:VCALENDAR' {
- continue
- }
- in_component = false
-
- // Parse the collected component
- match obj.comp_type {
- 'VEVENT' {
- mut event := calbox.Event{}
- parse_component(component_lines, mut event.CalendarComponent)!
- for comp_line in component_lines {
- name, params, value := parse_property(comp_line)!
- match name {
- 'DTSTART' { event.start_time = calbox.parse_datetime(value)! }
- 'DTEND' { event.end_time = calbox.parse_datetime(value)! }
- 'DURATION' { event.duration = value }
- 'RRULE' { event.rrule = parse_rrule(value)! }
- 'RDATE' { event.rdate << calbox.parse_datetime(value)! }
- 'EXDATE' { event.exdate << calbox.parse_datetime(value)! }
- 'TRANSP' { event.transp = calbox.parse_event_transp(value)! }
- 'ATTENDEE' { event.attendees << parse_attendee(value, params)! }
- 'ORGANIZER' { event.organizer = parse_attendee(value, params)! }
- else {}
- }
- }
- obj.event = event
- }
- 'VTODO' {
- mut todo := calbox.Todo{}
- parse_component(component_lines, mut todo.CalendarComponent)!
- for comp_line in component_lines {
- name, params, value := parse_property(comp_line)!
- match name {
- 'DTSTART' { todo.start_time = calbox.parse_datetime(value)! }
- 'DUE' { todo.due_time = calbox.parse_datetime(value)! }
- 'DURATION' { todo.duration = value }
- 'COMPLETED' { todo.completed = calbox.parse_datetime(value)! }
- 'PERCENT-COMPLETE' { todo.percent = value.int() }
- 'RRULE' { todo.rrule = parse_rrule(value)! }
- 'ATTENDEE' { todo.attendees << parse_attendee(value, params)! }
- 'ORGANIZER' { todo.organizer = parse_attendee(value, params)! }
- else {}
- }
- }
- obj.todo = todo
- }
- 'VJOURNAL' {
- mut journal := calbox.Journal{}
- parse_component(component_lines, mut journal.CalendarComponent)!
- for comp_line in component_lines {
- name, params, value := parse_property(comp_line)!
- match name {
- 'DTSTART' { journal.start_time = calbox.parse_datetime(value)! }
- 'ATTENDEE' { journal.attendees << parse_attendee(value, params)! }
- 'ORGANIZER' { journal.organizer = parse_attendee(value, params)! }
- else {}
- }
- }
- obj.journal = journal
- }
- else {}
- }
-
- component_lines.clear()
- continue
- }
-
- if in_component {
- component_lines << line
- }
- }
-
- return obj
-}
-
-// Folds a line according to iCalendar spec (max 75 chars)
-fn fold_line(line string) string {
- if line.len <= 75 {
- return line
- }
-
- mut result := []string{}
- mut current := line[0..75]
- mut remaining := line[75..]
- result << current
-
- for remaining.len > 0 {
- if remaining.len <= 74 {
- result << ' ${remaining}'
- break
- }
- current = remaining[0..74]
- remaining = remaining[74..]
- result << ' ${current}'
- }
-
- return result.join('\r\n')
-}
-
-// Formats a property with optional parameters
-fn format_property(name string, params map[string]string, value string) string {
- mut param_str := ''
- if params.len > 0 {
- param_parts := params.keys().map(fn (k string, v map[string]string) string {
- return '${k}=${v[k]}'
- })
- param_str = ';${param_parts.join(';')}'
- }
-
- line := '${name}${param_str}:${value}'
- return fold_line(line)
-}
-
-// Formats attendee properties
-fn format_attendee(a calbox.Attendee) string {
- mut props := []string{}
-
- props << 'ROLE=${a.role.str()}'
- props << 'PARTSTAT=${a.partstat.str()}'
-
- if a.rsvp {
- props << 'RSVP=TRUE'
- }
- if a.name != '' {
- props << 'CN=${a.name}'
- }
-
- param_str := if props.len > 0 { ';${props.join(';')}' } else { '' }
- return 'ATTENDEE${param_str}:mailto:${a.email}'
-}
-
-// Formats a recurrence rule
-fn format_rrule(r calbox.RecurrenceRule) string {
- mut parts := []string{}
- parts << 'FREQ=${r.frequency.str()}'
-
- if r.interval > 1 {
- parts << 'INTERVAL=${r.interval}'
- }
-
- if count := r.count {
- parts << 'COUNT=${count}'
- }
-
- if until := r.until {
- parts << 'UNTIL=${format_datetime(until)}'
- }
-
- if r.by_day.len > 0 {
- parts << 'BYDAY=${r.by_day.join(',')}'
- }
-
- if r.by_month.len > 0 {
- parts << 'BYMONTH=${r.by_month.map(it.str()).join(',')}'
- }
-
- if r.by_monthday.len > 0 {
- parts << 'BYMONTHDAY=${r.by_monthday.map(it.str()).join(',')}'
- }
-
- if r.week_start != '' {
- parts << 'WKST=${r.week_start}'
- }
-
- return 'RRULE:${parts.join(';')}'
-}
-
-// Formats alarm properties
-fn format_alarm(a calbox.Alarm) string {
- mut lines := []string{}
- lines << 'BEGIN:VALARM'
- lines << 'ACTION:${a.action.str()}'
- lines << 'TRIGGER:${a.trigger}'
-
- if a.description != '' {
- lines << 'DESCRIPTION:${a.description}'
- }
-
- if a.summary != '' {
- lines << 'SUMMARY:${a.summary}'
- }
-
- for attendee in a.attendees {
- lines << format_attendee(attendee)
- }
-
- for attach in a.attach {
- lines << 'ATTACH:${attach}'
- }
-
- lines << 'END:VALARM'
- return lines.join('\r\n')
-}
-
-// Formats common component properties
-fn format_component(c calbox.CalendarComponent) []string {
- mut lines := []string{}
-
- lines << 'UID:${c.uid}'
- lines << 'DTSTAMP:${format_datetime(c.created)}'
-
- if c.summary != '' {
- lines << 'SUMMARY:${c.summary}'
- }
-
- if c.description != '' {
- lines << 'DESCRIPTION:${c.description}'
- }
-
- if c.categories.len > 0 {
- lines << 'CATEGORIES:${c.categories.join(',')}'
- }
-
- lines << 'STATUS:${c.status.str()}'
- lines << 'CLASS:${c.class.str()}'
-
- if c.url != '' {
- lines << 'URL:${c.url}'
- }
-
- if c.location != '' {
- lines << 'LOCATION:${c.location}'
- }
-
- if geo := c.geo {
- lines << 'GEO:${geo.latitude};${geo.longitude}'
- }
-
- for alarm in c.alarms {
- lines << format_alarm(alarm)
- }
-
- return lines
-}
-
-// Converts an event to iCalendar format
-pub fn to_ical_event(event calbox.Event) string {
- mut lines := []string{}
- lines << 'BEGIN:VEVENT'
-
- // Add common properties
- lines << format_component(event.CalendarComponent)
-
- // Add event-specific properties
- lines << format_datetime_property('DTSTART', map[string]string{}, event.start_time)
-
- if end := event.end_time {
- lines << format_datetime_property('DTEND', map[string]string{}, end)
- } else if dur := event.duration {
- lines << format_property('DURATION', map[string]string{}, dur)
- }
-
- lines << 'TRANSP:${event.transp.str()}'
-
- if rule := event.rrule {
- lines << format_rrule(rule)
- }
-
- for ts in event.rdate {
- lines << 'RDATE:${format_datetime(ts)}'
- }
-
- for ts in event.exdate {
- lines << 'EXDATE:${format_datetime(ts)}'
- }
-
- for attendee in event.attendees {
- lines << format_attendee(attendee)
- }
-
- if organizer := event.organizer {
- lines << format_attendee(organizer).replace('ATTENDEE:', 'ORGANIZER:')
- }
-
- lines << 'END:VEVENT'
- return lines.join('\r\n')
-}
-
-// Converts a todo to iCalendar format
-pub fn to_ical_todo(todo calbox.Todo) string {
- mut lines := []string{}
- lines << 'BEGIN:VTODO'
-
- // Add common properties
- lines << format_component(todo.CalendarComponent)
-
- // Add todo-specific properties
- if start := todo.start_time {
- lines << format_datetime_property('DTSTART', map[string]string{}, start)
- }
-
- if due := todo.due_time {
- lines << format_datetime_property('DUE', map[string]string{}, due)
- }
-
- if dur := todo.duration {
- lines << format_property('DURATION', map[string]string{}, dur)
- }
-
- if completed := todo.completed {
- lines << format_datetime_property('COMPLETED', map[string]string{}, completed)
- }
-
- if percent := todo.percent {
- lines << 'PERCENT-COMPLETE:${percent}'
- }
-
- if rule := todo.rrule {
- lines << format_rrule(rule)
- }
-
- for attendee in todo.attendees {
- lines << format_attendee(attendee)
- }
-
- if organizer := todo.organizer {
- lines << format_attendee(organizer).replace('ATTENDEE:', 'ORGANIZER:')
- }
-
- lines << 'END:VTODO'
- return lines.join('\r\n')
-}
-
-// Converts a journal entry to iCalendar format
-pub fn to_ical_journal(journal calbox.Journal) string {
- mut lines := []string{}
- lines << 'BEGIN:VJOURNAL'
-
- // Add common properties
- lines << format_component(journal.CalendarComponent)
-
- // Add journal-specific properties
- lines << 'DTSTART:${format_datetime(journal.start_time)}'
-
- for attendee in journal.attendees {
- lines << format_attendee(attendee)
- }
-
- if organizer := journal.organizer {
- lines << format_attendee(organizer).replace('ATTENDEE:', 'ORGANIZER:')
- }
-
- lines << 'END:VJOURNAL'
- return lines.join('\r\n')
-}
-
-// Converts a calendar object to iCalendar format
-pub fn to_ical(obj calbox.CalendarObject) string {
- mut lines := []string{}
- lines << 'BEGIN:VCALENDAR'
- lines << 'VERSION:2.0'
- lines << 'PRODID:-//HeroLib//CalDAV Client//EN'
-
- match obj.comp_type {
- 'VEVENT' {
- if event := obj.event {
- lines << to_ical_event(event)
- }
- }
- 'VTODO' {
- if todo := obj.todo {
- lines << to_ical_todo(todo)
- }
- }
- 'VJOURNAL' {
- if journal := obj.journal {
- lines << to_ical_journal(journal)
- }
- }
- else {}
- }
-
- lines << 'END:VCALENDAR'
- return lines.join('\r\n')
-}
diff --git a/lib/servers/calendar/caldav/ical_test.v b/lib/servers/calendar/caldav/ical_test.v
deleted file mode 100644
index 597ad494..00000000
--- a/lib/servers/calendar/caldav/ical_test.v
+++ /dev/null
@@ -1,325 +0,0 @@
-module caldav
-
-import calendar.calbox
-
-fn test_format_event() {
- // Create a test event with all fields
- event := calbox.Event{
- CalendarComponent: calbox.CalendarComponent{
- uid: 'test@example.com'
- created: 1708074000 // 2024-02-16 10:00:00 UTC
- modified: 1708074000
- summary: 'Test Event'
- description: 'Test Description'
- categories: ['Work', 'Meeting']
- status: .confirmed
- class: .public
- location: 'Conference Room'
- alarms: [
- calbox.Alarm{
- action: .display
- trigger: '-PT15M'
- description: 'Meeting starts in 15 minutes'
- },
- ]
- }
- start_time: 1708074000
- end_time: 1708077600 // 1 hour later
- transp: .opaque
- attendees: [
- calbox.Attendee{
- email: 'john@example.com'
- name: 'John Doe'
- role: .req_participant
- partstat: .accepted
- rsvp: true
- },
- ]
- organizer: calbox.Attendee{
- email: 'boss@example.com'
- name: 'The Boss'
- role: .chair
- partstat: .accepted
- }
- }
-
- obj := calbox.CalendarObject{
- comp_type: 'VEVENT'
- event: event
- }
-
- ical := to_ical(obj)
-
- // Verify required fields
- assert ical.contains('BEGIN:VCALENDAR')
- assert ical.contains('VERSION:2.0')
- assert ical.contains('BEGIN:VEVENT')
- assert ical.contains('UID:test@example.com')
- assert ical.contains('DTSTART:20240216T100000Z')
- assert ical.contains('DTEND:20240216T110000Z')
- assert ical.contains('SUMMARY:Test Event')
- assert ical.contains('STATUS:CONFIRMED')
- assert ical.contains('CLASS:PUBLIC')
- assert ical.contains('TRANSP:OPAQUE')
- assert ical.contains('END:VEVENT')
- assert ical.contains('END:VCALENDAR')
-
- // Parse back
- parsed := from_ical(ical)!
- assert parsed.comp_type == 'VEVENT'
-
- if e := parsed.event {
- assert e.uid == event.uid
- assert e.summary == event.summary
- assert e.start_time == event.start_time
- assert e.end_time? == event.end_time?
- assert e.status == event.status
- assert e.class == event.class
- assert e.transp == event.transp
- assert e.attendees.len == event.attendees.len
- assert e.attendees[0].role == event.attendees[0].role
- assert e.attendees[0].partstat == event.attendees[0].partstat
- assert e.organizer?.role == event.organizer?.role
- } else {
- assert false, 'Failed to parse event'
- }
-}
-
-fn test_format_recurring_event() {
- // Create a recurring event
- event := calbox.Event{
- CalendarComponent: calbox.CalendarComponent{
- uid: 'recurring@example.com'
- created: 1708074000
- summary: 'Daily Meeting'
- status: .confirmed
- class: .public
- }
- start_time: 1708074000
- duration: 'PT1H'
- transp: .opaque
- rrule: calbox.RecurrenceRule{
- frequency: .daily
- interval: 1
- count: 5
- by_day: ['MO', 'WE', 'FR']
- }
- }
-
- obj := calbox.CalendarObject{
- comp_type: 'VEVENT'
- event: event
- }
-
- ical := to_ical(obj)
-
- // Verify recurrence fields
- assert ical.contains('RRULE:FREQ=DAILY;INTERVAL=1;COUNT=5;BYDAY=MO,WE,FR')
- assert ical.contains('DURATION:PT1H')
-
- // Parse back
- parsed := from_ical(ical)!
- if e := parsed.event {
- assert e.duration? == event.duration?
- if rule := e.rrule {
- assert rule.frequency == .daily
- assert rule.interval == 1
- assert rule.count? == 5
- assert rule.by_day == ['MO', 'WE', 'FR']
- } else {
- assert false, 'Failed to parse recurrence rule'
- }
- } else {
- assert false, 'Failed to parse event'
- }
-}
-
-fn test_format_todo() {
- // Create a todo
- todo := calbox.Todo{
- CalendarComponent: calbox.CalendarComponent{
- uid: 'todo@example.com'
- created: 1708074000
- summary: 'Test Todo'
- status: .needs_action
- class: .private
- }
- due_time: 1708160400 // Next day
- percent: 0
- }
-
- obj := calbox.CalendarObject{
- comp_type: 'VTODO'
- todo: todo
- }
-
- ical := to_ical(obj)
-
- // Verify todo fields
- assert ical.contains('BEGIN:VTODO')
- assert ical.contains('DUE:20240217T100000Z')
- assert ical.contains('PERCENT-COMPLETE:0')
- assert ical.contains('STATUS:NEEDS-ACTION')
- assert ical.contains('CLASS:PRIVATE')
-
- // Parse back
- parsed := from_ical(ical)!
- if t := parsed.todo {
- assert t.uid == todo.uid
- assert t.summary == todo.summary
- assert t.due_time? == todo.due_time?
- assert t.percent? == todo.percent?
- assert t.status == todo.status
- assert t.class == todo.class
- } else {
- assert false, 'Failed to parse todo'
- }
-}
-
-fn test_format_journal() {
- // Create a journal entry
- journal := calbox.Journal{
- CalendarComponent: calbox.CalendarComponent{
- uid: 'journal@example.com'
- created: 1708074000
- summary: 'Test Journal'
- description: 'Today we discussed...'
- categories: ['Notes', 'Work']
- status: .draft
- class: .confidential
- }
- start_time: 1708074000
- }
-
- obj := calbox.CalendarObject{
- comp_type: 'VJOURNAL'
- journal: journal
- }
-
- ical := to_ical(obj)
-
- // Verify journal fields
- assert ical.contains('BEGIN:VJOURNAL')
- assert ical.contains('DTSTART:20240216T100000Z')
- assert ical.contains('CATEGORIES:Notes,Work')
- assert ical.contains('STATUS:DRAFT')
- assert ical.contains('CLASS:CONFIDENTIAL')
-
- // Parse back
- parsed := from_ical(ical)!
- if j := parsed.journal {
- assert j.uid == journal.uid
- assert j.summary == journal.summary
- assert j.description == journal.description
- assert j.categories == journal.categories
- assert j.start_time == journal.start_time
- assert j.status == journal.status
- assert j.class == journal.class
- } else {
- assert false, 'Failed to parse journal'
- }
-}
-
-fn test_parse_attendees() {
- ical := 'BEGIN:VCALENDAR
-VERSION:2.0
-BEGIN:VEVENT
-UID:test@example.com
-DTSTAMP:20240216T100000Z
-DTSTART:20240216T100000Z
-DTEND:20240216T110000Z
-SUMMARY:Test Event
-ATTENDEE;CN=John Doe;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;RSVP=TRUE:mailto:john@example.com
-ORGANIZER;CN=The Boss;ROLE=CHAIR;PARTSTAT=ACCEPTED:mailto:boss@example.com
-END:VEVENT
-END:VCALENDAR'
-
- obj := from_ical(ical)!
- if event := obj.event {
- assert event.attendees.len == 1
- attendee := event.attendees[0]
- assert attendee.email == 'john@example.com'
- assert attendee.name == 'John Doe'
- assert attendee.role == .req_participant
- assert attendee.partstat == .accepted
- assert attendee.rsvp == true
-
- if org := event.organizer {
- assert org.email == 'boss@example.com'
- assert org.name == 'The Boss'
- assert org.role == .chair
- assert org.partstat == .accepted
- } else {
- assert false, 'Failed to parse organizer'
- }
- } else {
- assert false, 'Failed to parse event'
- }
-}
-
-fn test_parse_alarms() {
- ical := 'BEGIN:VCALENDAR
-VERSION:2.0
-BEGIN:VEVENT
-UID:test@example.com
-DTSTAMP:20240216T100000Z
-DTSTART:20240216T100000Z
-DTEND:20240216T110000Z
-SUMMARY:Test Event
-BEGIN:VALARM
-ACTION:DISPLAY
-TRIGGER:-PT15M
-DESCRIPTION:Meeting starts in 15 minutes
-END:VALARM
-END:VEVENT
-END:VCALENDAR'
-
- obj := from_ical(ical)!
- if event := obj.event {
- assert event.alarms.len == 1
- alarm := event.alarms[0]
- assert alarm.action == .display
- assert alarm.trigger == '-PT15M'
- assert alarm.description == 'Meeting starts in 15 minutes'
- } else {
- assert false, 'Failed to parse event'
- }
-}
-
-fn test_line_folding() {
- // Test long description that should be folded
- event := calbox.Event{
- CalendarComponent: calbox.CalendarComponent{
- uid: 'test@example.com'
- created: 1708074000
- summary: 'Test Event'
- description: 'This is a very long description that should be folded into multiple lines according to the iCalendar specification which states that lines longer than 75 characters should be folded'
- status: .confirmed
- class: .public
- }
- start_time: 1708074000
- end_time: 1708077600
- transp: .opaque
- }
-
- obj := calbox.CalendarObject{
- comp_type: 'VEVENT'
- event: event
- }
-
- ical := to_ical(obj)
- lines := ical.split_into_lines()
-
- // Verify no line is longer than 75 characters
- for line in lines {
- assert line.len <= 75, 'Line exceeds 75 characters: ${line}'
- }
-
- // Parse back and verify description is reconstructed
- parsed := from_ical(ical)!
- if e := parsed.event {
- assert e.description == event.description
- } else {
- assert false, 'Failed to parse event'
- }
-}
diff --git a/lib/servers/calendar/caldav/methods.v b/lib/servers/calendar/caldav/methods.v
deleted file mode 100644
index ede6210d..00000000
--- a/lib/servers/calendar/caldav/methods.v
+++ /dev/null
@@ -1,146 +0,0 @@
-module caldav
-
-import calendar.calbox
-
-// Handles MKCALENDAR request
-pub fn handle_mkcalendar(path string, props map[string]string, principal Principal) !&calbox.CalBox {
- // Check preconditions
- check_mkcalendar_preconditions(path, props)!
-
- // Create calendar collection
- mut cal := calbox.new(props['displayname'] or { path.all_after_last('/') })
-
- // Set properties
- if desc := props[calendar_description] {
- cal.description = desc
- }
- if tz := props[calendar_timezone] {
- cal.timezone = tz
- }
- if components := get_prop_array(props, supported_calendar_component_set) {
- cal.supported_components = components
- }
-
- // Set ACL
- cal.acl = new_acl()
- cal.acl.add_entry(principal, [admin], false, true)
-
- return cal
-}
-
-// Handles PUT request
-pub fn handle_put(cal &calbox.CalBox, obj calbox.CalendarObject, principal Principal) !bool {
- // Check privileges
- if !cal.acl.can_write(principal) {
- return error(err_no_privilege)
- }
-
- // Check preconditions
- check_put_preconditions(cal, obj)!
-
- // Add/update object
- cal.put(obj)!
-
- return true
-}
-
-// Handles DELETE request
-pub fn handle_delete(cal &calbox.CalBox, uid string, principal Principal) !bool {
- // Check privileges
- if !cal.acl.can_unbind(principal) {
- return error(err_no_privilege)
- }
-
- // Delete object
- cal.delete(uid)!
-
- return true
-}
-
-// Handles COPY request
-pub fn handle_copy(src_cal &calbox.CalBox, dst_cal &calbox.CalBox, uid string, principal Principal) !bool {
- // Check source privileges
- if !src_cal.acl.can_read(principal) {
- return error(err_no_privilege)
- }
-
- // Check destination privileges
- if !dst_cal.acl.can_bind(principal) {
- return error(err_no_privilege)
- }
-
- // Get source object
- obj := src_cal.get_by_uid(uid) or { return error(err_resource_not_found) }
-
- // Check preconditions
- check_copy_move_preconditions(src_cal, dst_cal, obj)!
-
- // Copy object
- dst_cal.put(obj)!
-
- return true
-}
-
-// Handles MOVE request
-pub fn handle_move(src_cal &calbox.CalBox, dst_cal &calbox.CalBox, uid string, principal Principal) !bool {
- // Check source privileges
- if !src_cal.acl.can_unbind(principal) {
- return error(err_no_privilege)
- }
-
- // Check destination privileges
- if !dst_cal.acl.can_bind(principal) {
- return error(err_no_privilege)
- }
-
- // Get source object
- obj := src_cal.get_by_uid(uid) or { return error(err_resource_not_found) }
-
- // Check preconditions
- check_copy_move_preconditions(src_cal, dst_cal, obj)!
-
- // Move object
- dst_cal.put(obj)!
- src_cal.delete(uid)!
-
- return true
-}
-
-// Handles PROPFIND request
-pub fn handle_propfind(cal &calbox.CalBox, props []string, principal Principal) !map[string]string {
- // Check privileges
- if !cal.acl.can_read(principal) {
- return error(err_no_privilege)
- }
-
- mut result := map[string]string{}
-
- // Get requested properties
- for prop in props {
- if value := get_prop_string(cal.props, prop) {
- result[prop] = value
- }
- }
-
- return result
-}
-
-// Handles PROPPATCH request
-pub fn handle_proppatch(mut cal calbox.CalBox, props map[string]string, principal Principal) !bool {
- // Check privileges
- if !cal.acl.can_write_props(principal) {
- return error(err_no_privilege)
- }
-
- // Validate and set properties
- for name, value in props {
- match name {
- calendar_timezone { validate_calendar_timezone(value)! }
- supported_calendar_component_set { validate_supported_component_set(value.split(','))! }
- else {}
- }
- set_prop(mut cal.props, name, value)
- }
-
- return true
-}
diff --git a/lib/servers/calendar/caldav/preconditions.v b/lib/servers/calendar/caldav/preconditions.v
deleted file mode 100644
index f7f48a4a..00000000
--- a/lib/servers/calendar/caldav/preconditions.v
+++ /dev/null
@@ -1,125 +0,0 @@
-module caldav
-
-import calendar.calbox
-
-// Checks preconditions for MKCALENDAR
-pub fn check_mkcalendar_preconditions(path string, props map[string]string) !bool {
- // Resource must not exist
- if resource_exists(path) {
- return error(err_resource_must_be_null)
- }
-
- // Valid calendar timezone
- if tz := props[calendar_timezone] {
- validate_calendar_timezone(tz)!
- }
-
- // Valid component set
- if comp_set := get_prop_array(props, supported_calendar_component_set) {
- validate_supported_component_set(comp_set)!
- }
-
- return true
-}
-
-// Checks preconditions for PUT
-pub fn check_put_preconditions(cal &calbox.CalBox, obj calbox.CalendarObject) !bool {
- // Supported calendar data
- validate_calendar_data('text/calendar', '2.0')!
-
- // Valid calendar data
- if !is_valid_calendar_data(obj) {
- return error(err_valid_calendar_data)
- }
-
- // Valid calendar object
- if !is_valid_calendar_object(obj) {
- return error(err_valid_calendar_object)
- }
-
- // Supported component
- if !cal.supports_component(obj.comp_type) {
- return error(err_supported_component)
- }
-
- // Resource size
- if max_size := cal.max_resource_size {
- if obj.size() > max_size {
- return error('Resource size exceeds maximum allowed')
- }
- }
-
- // Date range
- if !check_date_range(cal, obj) {
- return error('Date/time outside allowed range')
- }
-
- // Instance count
- if !check_instance_count(cal, obj) {
- return error('Too many recurrence instances')
- }
-
- // Attendee count
- if !check_attendee_count(cal, obj) {
- return error('Too many attendees')
- }
-
- // UID conflict
- if existing := cal.find_by_uid(obj.uid()) {
- if existing.uid() != obj.uid() {
- return error_with_href(err_uid_conflict, existing.href())
- }
- }
-
- return true
-}
-
-// Checks preconditions for COPY/MOVE
-pub fn check_copy_move_preconditions(src_cal &calbox.CalBox, dst_cal &calbox.CalBox, obj calbox.CalendarObject) !bool {
- // Valid calendar collection location
- if !is_valid_calendar_location(dst_cal.path) {
- return error(err_calendar_collection_location)
- }
-
- // Check PUT preconditions on destination
- check_put_preconditions(dst_cal, obj)!
-
- return true
-}
-
-// Helper functions
-
-fn resource_exists(path string) bool {
- // TODO: Implement resource existence check
- return false
-}
-
-fn is_valid_calendar_data(obj calbox.CalendarObject) bool {
- // TODO: Implement calendar data validation
- return true
-}
-
-fn is_valid_calendar_object(obj calbox.CalendarObject) bool {
- // TODO: Implement calendar object validation
- return true
-}
-
-fn is_valid_calendar_location(path string) bool {
- // TODO: Implement calendar location validation
- return true
-}
-
-fn check_date_range(cal &calbox.CalBox, obj calbox.CalendarObject) bool {
- // TODO: Implement date range check
- return true
-}
-
-fn check_instance_count(cal &calbox.CalBox, obj calbox.CalendarObject) bool {
- // TODO: Implement instance count check
- return true
-}
-
-fn check_attendee_count(cal &calbox.CalBox, obj calbox.CalendarObject) bool {
- // TODO: Implement attendee count check
- return true
-}
diff --git a/lib/servers/calendar/caldav/props.v b/lib/servers/calendar/caldav/props.v
deleted file mode 100644
index a854cbec..00000000
--- a/lib/servers/calendar/caldav/props.v
+++ /dev/null
@@ -1,116 +0,0 @@
-module caldav
-
-// CalDAV property names
-pub const calendar_description = 'calendar-description'
-pub const calendar_timezone = 'calendar-timezone'
-pub const supported_calendar_component_set = 'supported-calendar-component-set'
-pub const supported_calendar_data = 'supported-calendar-data'
-pub const max_resource_size = 'max-resource-size'
-pub const min_date_time = 'min-date-time'
-pub const max_date_time = 'max-date-time'
-pub const max_instances = 'max-instances'
-pub const max_attendees_per_instance = 'max-attendees-per-instance'
-pub const calendar_home_set = 'calendar-home-set'
-
-// Property validation errors
-pub const err_invalid_timezone = 'Invalid timezone: must be a valid iCalendar object containing a single VTIMEZONE component'
-pub const err_invalid_component_set = 'Invalid component set: must contain at least one component type'
-pub const err_invalid_calendar_data = 'Invalid calendar data: must specify a supported media type'
-pub const err_invalid_resource_size = 'Invalid resource size: must be a positive integer'
-pub const err_invalid_date_time = 'Invalid date/time: must be a valid UTC date-time value'
-pub const err_invalid_instances = 'Invalid instances value: must be a positive integer'
-pub const err_invalid_attendees = 'Invalid attendees value: must be a positive integer'
-
-// Property validation functions
-
-// Validates a calendar timezone property value
-pub fn validate_calendar_timezone(value string) ! {
- // TODO: Implement timezone validation
- // Should parse value as iCalendar and verify it contains exactly one VTIMEZONE
- if value.len == 0 {
- return error(err_invalid_timezone)
- }
-}
-
-// Validates a supported calendar component set property value
-pub fn validate_supported_component_set(components []string) ! {
- if components.len == 0 {
- return error(err_invalid_component_set)
- }
-
- valid := ['VEVENT', 'VTODO', 'VJOURNAL', 'VFREEBUSY']
- for comp in components {
- if comp !in valid {
- return error(err_invalid_component_set)
- }
- }
-}
-
-// Validates a supported calendar data property value
-pub fn validate_calendar_data(content_type string, version string) ! {
- if content_type != 'text/calendar' || version != '2.0' {
- return error(err_invalid_calendar_data)
- }
-}
-
-// Validates a max resource size property value
-pub fn validate_max_resource_size(size int) ! {
- if size <= 0 {
- return error(err_invalid_resource_size)
- }
-}
-
-// Validates a min/max date time property value
-pub fn validate_date_time(value string) ! {
- // TODO: Implement UTC date-time validation
- if value.len == 0 {
- return error(err_invalid_date_time)
- }
-}
-
-// Validates a max instances property value
-pub fn validate_max_instances(count int) ! {
- if count <= 0 {
- return error(err_invalid_instances)
- }
-}
-
-// Validates a max attendees per instance property value
-pub fn validate_max_attendees(count int) ! {
- if count <= 0 {
- return error(err_invalid_attendees)
- }
-}
-
-// Property value getters/setters
-
-// Gets a property value as string
-pub fn get_prop_string(props map[string]string, name string) ?string {
- return props[name]
-}
-
-// Gets a property value as int
-pub fn get_prop_int(props map[string]string, name string) ?int {
- if value := props[name] {
- return value.int()
- }
- return none
-}
-
-// Gets a property value as string array
-pub fn get_prop_array(props map[string]string, name string) ?[]string {
- if value := props[name] {
- return value.split(',')
- }
- return none
-}
-
-// Sets a property value
-pub fn set_prop(mut props map[string]string, name string, value string) {
- props[name] = value
-}
-
-// Removes a property
-pub fn remove_prop(mut props map[string]string, name string) {
- props.delete(name)
-}
diff --git a/lib/servers/calendar/caldav/protocol.v b/lib/servers/calendar/caldav/protocol.v
deleted file mode 100644
index ac9bc6d8..00000000
--- a/lib/servers/calendar/caldav/protocol.v
+++ /dev/null
@@ -1,105 +0,0 @@
-module caldav
-
-import calendar.calbox
-
-// Represents a CalDAV server instance
-pub struct Server {
-mut:
- collections map[string]&calbox.CalBox // Map of calendar collections by path
-}
-
-// Creates a new CalDAV server instance
-pub fn new() &Server {
- return &Server{
- collections: map[string]&calbox.CalBox{}
- }
-}
-
-// Adds a calendar collection to the server
-pub fn (mut s Server) add_collection(path string, cal &calbox.CalBox) {
- s.collections[path] = cal
-}
-
-// Gets a calendar collection by path
-pub fn (s Server) get_collection(path string) ?&calbox.CalBox {
- return s.collections[path] or { none }
-}
-
-// Handles a MKCALENDAR request
-pub fn (mut s Server) handle_mkcalendar(path string, props map[string]string) !&calbox.CalBox {
- // Create new calendar collection
- mut cal := calbox.new(props['displayname'] or { path.all_after_last('/') })
-
- // Set optional properties
- if desc := props['calendar-description'] {
- cal.description = desc
- }
- if tz := props['calendar-timezone'] {
- cal.timezone = tz
- }
- if components := props['supported-calendar-component-set'] {
- cal.supported_components = components.split(',')
- }
-
- // Add to server
- s.add_collection(path, cal)
-
- return cal
-}
-
-// Handles a calendar-query REPORT request
-pub fn (s Server) handle_calendar_query(path string, filter CalendarQueryFilter) ![]calbox.CalendarObject {
- // Get calendar collection
- cal := s.get_collection(path) or { return error('Calendar not found') }
-
- // Apply filter
- mut results := []calbox.CalendarObject{}
-
- if filter.time_range != none {
- tr := filter.time_range or { return error('Invalid time range') }
- results = cal.find_by_time(calbox.TimeRange{
- start: tr.start
- end: tr.end
- })!
- } else {
- results = cal.list()!
- }
-
- return results
-}
-
-// Handles a calendar-multiget REPORT request
-pub fn (s Server) handle_calendar_multiget(path string, hrefs []string) ![]calbox.CalendarObject {
- // Get calendar collection
- cal := s.get_collection(path) or { return error('Calendar not found') }
-
- mut results := []calbox.CalendarObject{}
-
- // Get requested resources
- for href in hrefs {
- obj_path := href.all_after(path)
- if obj := cal.get_by_uid(obj_path) {
- results << obj
- }
- }
-
- return results
-}
-
-// Handles a free-busy-query REPORT request
-pub fn (s Server) handle_freebusy_query(path string, tr calbox.TimeRange) ![]calbox.TimeRange {
- // Get calendar collection
- cal := s.get_collection(path) or { return error('Calendar not found') }
-
- // Get free/busy info
- return cal.get_freebusy(tr)
-}
-
-// Filter for calendar-query REPORT
-pub struct CalendarQueryFilter {
-pub mut:
- time_range ?calbox.TimeRange
- comp_type string
- prop_name string
- text_match string
-}
diff --git a/lib/servers/calendar/caldav/reports.v b/lib/servers/calendar/caldav/reports.v
deleted file mode 100644
index 64aafe76..00000000
--- a/lib/servers/calendar/caldav/reports.v
+++ /dev/null
@@ -1,175 +0,0 @@
-module caldav
-
-import calendar.calbox
-
-// Report types
-pub const calendar_query = 'calendar-query'
-pub const calendar_multiget = 'calendar-multiget'
-pub const freebusy_query = 'free-busy-query'
-
-// Report request parameters
-pub struct ReportParams {
-pub mut:
- depth int // Depth header value
- props []string // Properties to return
- filter CalendarQueryFilter // Query filter
- hrefs []string // Resource hrefs for multiget
- timezone string // Timezone for floating time conversion
- expand bool // Whether to expand recurrences
- limit_set bool // Whether to limit recurrence/freebusy set
- time_range ?calbox.TimeRange // Time range for limiting results
-}
-
-// Report response
-pub struct ReportResponse {
-pub mut:
- status int // HTTP status code
- objects []calbox.CalendarObject // Calendar objects
- ranges []calbox.TimeRange // Free/busy ranges
- error ?CalDAVError // Error if any
-}
-
-// Handles a calendar-query REPORT
-pub fn handle_calendar_query(cal &calbox.CalBox, params ReportParams) ReportResponse {
- mut response := ReportResponse{
- status: 207 // Multi-Status
- }
-
- // Check privileges
- if !cal.acl.can_read(params.principal) {
- response.status = 403
- response.error = err_forbidden_error(err_no_privilege)
- return response
- }
-
- // Apply filter
- objects := cal.find_by_filter(params.filter) or {
- response.status = 500
- response.error = new_error(500, err.str())
- return response
- }
-
- // Apply time range if specified
- if tr := params.time_range {
- for obj in objects {
- if obj.overlaps(tr) {
- response.objects << obj
- }
- }
- } else {
- response.objects = objects
- }
-
- // Expand recurrences if requested
- if params.expand {
- response.objects = expand_recurrences(response.objects, params.time_range)
- }
-
- // Limit recurrence set if requested
- if params.limit_set {
- response.objects = limit_recurrence_set(response.objects, params.time_range)
- }
-
- return response
-}
-
-// Handles a calendar-multiget REPORT
-pub fn handle_calendar_multiget(cal &calbox.CalBox, params ReportParams) ReportResponse {
- mut response := ReportResponse{
- status: 207 // Multi-Status
- }
-
- // Check privileges
- if !cal.acl.can_read(params.principal) {
- response.status = 403
- response.error = err_forbidden_error(err_no_privilege)
- return response
- }
-
- // Get requested resources
- for href in params.hrefs {
- if obj := cal.get_by_href(href) {
- response.objects << obj
- }
- }
-
- // Expand recurrences if requested
- if params.expand {
- response.objects = expand_recurrences(response.objects, params.time_range)
- }
-
- // Limit recurrence set if requested
- if params.limit_set {
- response.objects = limit_recurrence_set(response.objects, params.time_range)
- }
-
- return response
-}
-
-// Handles a free-busy-query REPORT
-pub fn handle_freebusy_query(cal &calbox.CalBox, params ReportParams) ReportResponse {
- mut response := ReportResponse{
- status: 200 // OK
- }
-
- // Check privileges
- if !cal.acl.can_read_freebusy(params.principal) {
- response.status = 403
- response.error = err_forbidden_error(err_no_privilege)
- return response
- }
-
- // Get time range
- tr := params.time_range or {
- response.status = 400
- response.error = new_error(400, 'Missing time range')
- return response
- }
-
- // Get free/busy ranges
- ranges := cal.get_freebusy(tr) or {
- response.status = 500
- response.error = new_error(500, err.str())
- return response
- }
-
- response.ranges = ranges
- return response
-}
-
-// Helper functions
-
-fn expand_recurrences(objects []calbox.CalendarObject, tr ?calbox.TimeRange) []calbox.CalendarObject {
- mut expanded := []calbox.CalendarObject{}
-
- for obj in objects {
- if obj.is_recurring() {
- if range := tr {
- expanded << obj.expand(range)
- } else {
- expanded << obj.expand_all()
- }
- } else {
- expanded << obj
- }
- }
-
- return expanded
-}
-
-fn limit_recurrence_set(objects []calbox.CalendarObject, tr ?calbox.TimeRange) []calbox.CalendarObject {
- if tr == none {
- return objects
- }
-
- mut limited := []calbox.CalendarObject{}
- range := tr or { return objects }
-
- for obj in objects {
- if obj.overlaps(range) {
- limited << obj
- }
- }
-
- return limited
-}
diff --git a/lib/servers/calendar/caldav/specs.md b/lib/servers/calendar/caldav/specs.md
deleted file mode 100644
index f4784d5c..00000000
--- a/lib/servers/calendar/caldav/specs.md
+++ /dev/null
@@ -1,5215 +0,0 @@
-
-
- Calendaring Extensions to WebDAV (CalDAV)
-
-Abstract
-
- This document defines extensions to the Web Distributed Authoring and
- Versioning (WebDAV) protocol to specify a standard way of accessing,
- managing, and sharing calendaring and scheduling information based on
- the iCalendar format.
-
-1. Introduction
-
- The concept of using HTTP and WebDAV as a basis for a calendar access
- protocol allows implementations to upload and download iCalendar objects,
- and use WebDAV to get listings of resources. This document proposes a way
- to model calendar data in WebDAV, with additional features to make an
- interoperable calendar access protocol.
-
-1.2. XML Namespaces and Processing
-
- Definitions of XML elements in this document use XML element type
- declarations (as found in XML Document Type Declarations), described
- in Section 3.2 of [W3C.REC-xml-20060816].
-
- The namespace "urn:ietf:params:xml:ns:caldav" is used for the XML
- elements defined in this specification. XML elements defined by individual
- implementations MUST NOT use the "urn:ietf:params:xml:ns:caldav"
- namespace, and instead should use a namespace that they control.
-
- The XML declarations used in this document do not include namespace
- information. Thus, implementers must not use these declarations as
- the only way to create valid CalDAV properties or to validate CalDAV
- XML element types. Some of the declarations refer to XML elements
- defined by WebDAV [RFC2518], which use the "DAV:" namespace.
- Wherever such XML elements appear, they are explicitly prefixed with
- "DAV:" to avoid confusion.
-
-
- Also note that some CalDAV XML element names are identical to WebDAV
- XML element names, though their namespace differs. Care must be
- taken not to confuse the two sets of names.
-
- Processing of XML by CalDAV clients and servers MUST follow the rules
- described in WebDAV specifications.
-
-1.3. Method Preconditions and Postconditions
-
- A "precondition" of a method describes the state of the server that
- must be true for that method to be performed. A "postcondition" of a
- method describes the state of the server that must be true after that
- method has been completed. If a method precondition or postcondition
- for a request is not satisfied, the response status of the request
- MUST either be 403 (Forbidden), if the request should not be repeated
- because it will always fail, or 409 (Conflict), if it is expected
- that the user might be able to resolve the conflict and resubmit the
- request.
-
- In order to allow better client handling of 403 and 409 responses, a
- distinct XML element type is associated with each method precondition
- and postcondition of a request. When a particular precondition is
- not satisfied or a particular postcondition cannot be achieved, the
- appropriate XML element MUST be returned as the child of a top-level
- DAV:error element in the response body, unless otherwise negotiated
- by the request.
-
-1. Requirements Overview
-
- This section lists what functionality is required of a CalDAV server.
- To advertise support for CalDAV, a server:
-
- o MUST support iCalendar as a media type for the calendar object
- resource format;
-
- o MUST support WebDAV Class 1;
-
- o MUST support WebDAV ACL with the additional privilege defined in
- this document;
-
- o MUST support transport over TLS;
-
- o MUST support ETags with additional requirements specified in this
- document;
-
- o MUST support all calendaring reports defined in this document;
-
- o MUST advertise support on all calendar collections and calendar
- object resources for the calendaring reports in the DAV:supported-
- report-set property.
-
- In addition, a server:
-
- o SHOULD support the MKCALENDAR method defined in Section 5.3.1 of
- this document.
-
-2. Calendaring Data Model
-
- One of the features that has made WebDAV a successful protocol is its
- firm data model. This makes it a useful framework for other
- applications such as calendaring. This specification follows the
- same pattern by developing all features based on a well-described
- data model.
-
- As a brief overview, a CalDAV calendar is modeled as a WebDAV
- collection with a defined structure; each calendar collection
- contains a number of resources representing calendar objects as its
- direct child resource. Each resource representing a calendar object
- (event, to-do, journal entry, or other calendar components) is called
- a "calendar object resource". Each calendar object resource and each
- calendar collection can be individually locked and have individual
- WebDAV properties. Requirements derived from this model are provided
- in Section 4.1 and Section 4.2.
-
-3.1. Calendar Server
-
- A CalDAV server is a calendaring-aware engine combined with a WebDAV
- repository. A WebDAV repository is a set of WebDAV collections,
- containing other WebDAV resources, within a unified URL namespace.
- For example, the repository "http://www.example.com/webdav/" may
- contain WebDAV collections and resources, all of which have URLs
- beginning with "http://www.example.com/webdav/". Note that the root
- URL, "http://www.example.com/", may not itself be a WebDAV repository
- (for example, if the WebDAV support is implemented through a servlet
- or other Web server extension).
-
- A WebDAV repository MAY include calendar data in some parts of its
- URL namespace, and non-calendaring data in other parts.
-
- A WebDAV repository can advertise itself as a CalDAV server if it
- supports the functionality defined in this specification at any point
-
-
- within the root of the repository. That might mean that calendaring
- data is spread throughout the repository and mixed with non-calendar
- data in nearby collections (e.g., calendar data may be found in
- /home/lisa/calendars/ as well as in /home/bernard/calendars/, and
- non-calendar data in /home/lisa/contacts/). Or, it might mean that
- calendar data can be found only in certain sections of the repository
- (e.g., /calendar/). Calendaring features are only required in the
- repository sections that are or contain calendar object resources.
- Therefore, a repository confining calendar data to the /calendar/
- collection would only need to support the CalDAV required features
- within that collection.
-
- The CalDAV server or repository is the canonical location for
- calendar data and state information. Clients may submit requests to
- change data or download data. Clients may store calendar objects
- offline and attempt to synchronize at a later time. However, clients
- MUST be prepared for calendar data on the server to change between
- the time of last synchronization and when attempting an update, as
- calendar collections may be shared and accessible via multiple
- clients. Entity tags and other features make this possible.
-
-3.2. Recurrence and the Data Model
-
- Recurrence is an important part of the data model because it governs
- how many resources are expected to exist. This specification models
- a recurring calendar component and its recurrence exceptions as a
- single resource. In this model, recurrence rules, recurrence dates,
- exception rules, and exception dates are all part of the data in a
- single calendar object resource. This model avoids problems of
- limiting how many recurrence instances to store in the repository,
- how to keep recurrence instances in sync with the recurring calendar
- component, and how to link recurrence exceptions with the recurring
- calendar component. It also results in less data to synchronize
- between client and server, and makes it easier to make changes to all
- recurrence instances or to a recurrence rule. It makes it easier to
- create a recurring calendar component and to delete all recurrence
- instances.
-
- Clients are not forced to retrieve information about all recurrence
- instances of a recurring component. The CALDAV:calendar-query and
- CALDAV:calendar-multiget reports defined in this document allow
- clients to retrieve only recurrence instances that overlap a given
- time range.
-
-
-1. Calendar Resources
-
-4.1. Calendar Object Resources
-
- Calendar object resources contained in calendar collections MUST NOT
- contain more than one type of calendar component (e.g., VEVENT,
- VTODO, VJOURNAL, VFREEBUSY, etc.) with the exception of VTIMEZONE
- components, which MUST be specified for each unique TZID parameter
- value specified in the iCalendar object. For instance, a calendar
- object resource can contain one VEVENT component and one VTIMEZONE
- component, but it cannot contain one VEVENT component and one VTODO
- component. Instead, the VEVENT and VTODO components would have to be
- stored in separate calendar object resources in the same collection.
-
- Calendar object resources contained in calendar collections MUST NOT
- specify the iCalendar METHOD property.
-
- The UID property value of the calendar components contained in a
- calendar object resource MUST be unique in the scope of the calendar
- collection in which they are stored.
-
- Calendar components in a calendar collection that have different UID
- property values MUST be stored in separate calendar object resources.
-
- Calendar components with the same UID property value, in a given
- calendar collection, MUST be contained in the same calendar object
- resource. This ensures that all components in a recurrence "set" are
- contained in the same calendar object resource. It is possible for a
- calendar object resource to just contain components that represent
- "overridden" instances (ones that modify the behavior of a regular
- instance, and thus include a RECURRENCE-ID property) without also
- including the "master" recurring component (the one that defines the
- recurrence "set" and does not contain any RECURRENCE-ID property).
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- For example, given the following iCalendar object:
-
- BEGIN:VCALENDAR
- PRODID:-//Example Corp.//CalDAV Client//EN
- VERSION:2.0
- BEGIN:VEVENT
- UID:1@example.com
- SUMMARY:One-off Meeting
- DTSTAMP:20041210T183904Z
- DTSTART:20041207T120000Z
- DTEND:20041207T130000Z
- END:VEVENT
- BEGIN:VEVENT
- UID:2@example.com
- SUMMARY:Weekly Meeting
- DTSTAMP:20041210T183838Z
- DTSTART:20041206T120000Z
- DTEND:20041206T130000Z
- RRULE:FREQ=WEEKLY
- END:VEVENT
- BEGIN:VEVENT
- UID:2@example.com
- SUMMARY:Weekly Meeting
- RECURRENCE-ID:20041213T120000Z
- DTSTAMP:20041210T183838Z
- DTSTART:20041213T130000Z
- DTEND:20041213T140000Z
- END:VEVENT
- END:VCALENDAR
-
- The VEVENT component with the UID value "1@example.com" would be
- stored in its own calendar object resource. The two VEVENT
- components with the UID value "2@example.com", which represent a
- recurring event where one recurrence instance has been overridden,
- would be stored in the same calendar object resource.
-
-4.2. Calendar Collection
-
- A calendar collection contains calendar object resources that
- represent calendar components within a calendar. A calendar
- collection is manifested to clients as a WebDAV resource collection
- identified by a URL. A calendar collection MUST report the DAV:
- collection and CALDAV:calendar XML elements in the value of the DAV:
- resourcetype property. The element type declaration for CALDAV:
- calendar is:
-
-
-
-
-
-
-
- A calendar collection can be created through provisioning (i.e.,
- automatically created when a user's account is provisioned), or it
- can be created with the MKCALENDAR method (see Section 5.3.1). This
- method can be useful for a user to create additional calendars (e.g.,
- soccer schedule) or for users to share a calendar (e.g., team events
- or conference rooms). However, note that this document doesn't
- define the purpose of extra calendar collections. Users must rely on
- non-standard cues to find out what a calendar collection is for, or
- use the CALDAV:calendar-description property defined in Section 5.2.1
- to provide such a cue.
-
- The following restrictions are applied to the resources within a
- calendar collection:
-
- a. Calendar collections MUST only contain calendar object resources
- and collections that are not calendar collections, i.e., the only
- "top-level" non-collection resources allowed in a calendar
- collection are calendar object resources. This ensures that
- calendar clients do not have to deal with non-calendar data in a
- calendar collection, though they do have to distinguish between
- calendar object resources and collections when using standard
- WebDAV techniques to examine the contents of a collection.
-
- b. Collections contained in calendar collections MUST NOT contain
- calendar collections at any depth, i.e., "nesting" of calendar
- collections within other calendar collections at any depth is not
- allowed. This specification does not define how collections
- contained in a calendar collection are used or how they relate to
- any calendar object resources contained in the calendar
- collection.
-
- Multiple calendar collections MAY be children of the same collection.
-
-5. Calendar Access Feature
-
-5.1. Calendar Access Support
-
- A server supporting the features described in this document MUST
- include "calendar-access" as a field in the DAV response header from
- an OPTIONS request on any resource that supports any calendar
- properties, reports, method, or privilege. A value of "calendar-
- access" in the DAV response header MUST indicate that the server
- supports all MUST level requirements specified in this document.
-
-
-
-
-
-
-
-
-
-5.1.1. Example: Using OPTIONS for the Discovery of Calendar Access
- Support
-
- >> Request <<
-
- OPTIONS /home/bernard/calendars/ HTTP/1.1
- Host: cal.example.com
-
- >> Response <<
-
- HTTP/1.1 200 OK
- Allow: OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, COPY, MOVE
- Allow: PROPFIND, PROPPATCH, LOCK, UNLOCK, REPORT, ACL
- DAV: 1, 2, access-control, calendar-access
- Date: Sat, 11 Nov 2006 09:32:12 GMT
- Content-Length: 0
-
- In this example, the OPTIONS method returns the value "calendar-
- access" in the DAV response header to indicate that the collection
- "/home/bernard/calendars/" supports the properties, reports, method,
- or privilege defined in this specification.
-
-5.2. Calendar Collection Properties
-
- This section defines properties for calendar collections.
-
-5.2.1. CALDAV:calendar-description Property
-
- Name: calendar-description
-
- Namespace: urn:ietf:params:xml:ns:caldav
-
- Purpose: Provides a human-readable description of the calendar
- collection.
-
- Conformance: This property MAY be defined on any calendar
- collection. If defined, it MAY be protected and SHOULD NOT be
- returned by a PROPFIND DAV:allprop request (as defined in Section
- 12.14.1 of [RFC2518]). An xml:lang attribute indicating the human
- language of the description SHOULD be set for this property by
- clients or through server provisioning. Servers MUST return any
- xml:lang attribute if set for the property.
-
- Description: If present, the property contains a description of the
- calendar collection that is suitable for presentation to a user.
- If not present, the client should assume no description for the
- calendar collection.
-
-
-
-
-
- Definition:
-
-
- PCDATA value: string
-
- Example:
-
- Calendrier de Mathilde Desruisseaux
-
-5.2.2. CALDAV:calendar-timezone Property
-
- Name: calendar-timezone
-
- Namespace: urn:ietf:params:xml:ns:caldav
-
- Purpose: Specifies a time zone on a calendar collection.
-
- Conformance: This property SHOULD be defined on all calendar
- collections. If defined, it SHOULD NOT be returned by a PROPFIND
- DAV:allprop request (as defined in Section 12.14.1 of [RFC2518]).
-
- Description: The CALDAV:calendar-timezone property is used to
- specify the time zone the server should rely on to resolve "date"
- values and "date with local time" values (i.e., floating time) to
- "date with UTC time" values. The server will require this
- information to determine if a calendar component scheduled with
- "date" values or "date with local time" values overlaps a CALDAV:
- time-range specified in a CALDAV:calendar-query REPORT. The
- server will also require this information to compute the proper
- FREEBUSY time period as "date with UTC time" in the VFREEBUSY
- component returned in a response to a CALDAV:free-busy-query
- REPORT request that takes into account calendar components
- scheduled with "date" values or "date with local time" values. In
- the absence of this property, the server MAY rely on the time zone
- of their choice.
-
- Note: The iCalendar data embedded within the CALDAV:calendar-
- timezone XML element MUST follow the standard XML character data
- encoding rules, including use of <, >, & etc. entity
- encoding or the use of a construct. In the
- later case, the iCalendar data cannot contain the character
- sequence "]]>", which is the end delimiter for the CDATA section.
-
-
-
-
-
-
-
-
- Definition:
-
-
- PCDATA value: an iCalendar object with exactly one VTIMEZONE
- component.
-
- Example:
-
- BEGIN:VCALENDAR
- PRODID:-//Example Corp.//CalDAV Client//EN
- VERSION:2.0
- BEGIN:VTIMEZONE
- TZID:US-Eastern
- LAST-MODIFIED:19870101T000000Z
- BEGIN:STANDARD
- DTSTART:19671029T020000
- RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
- TZOFFSETFROM:-0400
- TZOFFSETTO:-0500
- TZNAME:Eastern Standard Time (US & Canada)
- END:STANDARD
- BEGIN:DAYLIGHT
- DTSTART:19870405T020000
- RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
- TZOFFSETFROM:-0500
- TZOFFSETTO:-0400
- TZNAME:Eastern Daylight Time (US & Canada)
- END:DAYLIGHT
- END:VTIMEZONE
- END:VCALENDAR
-
-
-5.2.3. CALDAV:supported-calendar-component-set Property
-
- Name: supported-calendar-component-set
-
- Namespace: urn:ietf:params:xml:ns:caldav
-
- Purpose: Specifies the calendar component types (e.g., VEVENT,
- VTODO, etc.) that calendar object resources can contain in the
- calendar collection.
-
- Conformance: This property MAY be defined on any calendar
- collection. If defined, it MUST be protected and SHOULD NOT be
- returned by a PROPFIND DAV:allprop request (as defined in Section
- 12.14.1 of [RFC2518]).
-
-
-
-
-
- Description: The CALDAV:supported-calendar-component-set property is
- used to specify restrictions on the calendar component types that
- calendar object resources may contain in a calendar collection.
- Any attempt by the client to store calendar object resources with
- component types not listed in this property, if it exists, MUST
- result in an error, with the CALDAV:supported-calendar-component
- precondition (Section 5.3.2.1) being violated. Since this
- property is protected, it cannot be changed by clients using a
- PROPPATCH request. However, clients can initialize the value of
- this property when creating a new calendar collection with
- MKCALENDAR. The empty-element tag MUST
- only be specified if support for calendar object resources that
- only contain VTIMEZONE components is provided or desired. Support
- for VTIMEZONE components in calendar object resources that contain
- VEVENT or VTODO components is always assumed. In the absence of
- this property, the server MUST accept all component types, and the
- client can assume that all component types are accepted.
-
- Definition:
-
-
-
- Example:
-
-
-
-
-
-
-5.2.4. CALDAV:supported-calendar-data Property
-
- Name: supported-calendar-data
-
- Namespace: urn:ietf:params:xml:ns:caldav
-
- Purpose: Specifies what media types are allowed for calendar object
- resources in a calendar collection.
-
- Conformance: This property MAY be defined on any calendar
- collection. If defined, it MUST be protected and SHOULD NOT be
- returned by a PROPFIND DAV:allprop request (as defined in Section
- 12.14.1 of [RFC2518]).
-
- Description: The CALDAV:supported-calendar-data property is used to
- specify the media type supported for the calendar object resources
- contained in a given calendar collection (e.g., iCalendar version
- 2.0). Any attempt by the client to store calendar object
-
-
-
-
- resources with a media type not listed in this property MUST
- result in an error, with the CALDAV:supported-calendar-data
- precondition (Section 5.3.2.1) being violated. In the absence of
- this property, the server MUST only accept data with the media
- type "text/calendar" and iCalendar version 2.0, and clients can
- assume that the server will only accept this data.
-
- Definition:
-
-
-
- Example:
-
-
-
-
-
-5.2.5. CALDAV:max-resource-size Property
-
- Name: max-resource-size
-
- Namespace: urn:ietf:params:xml:ns:caldav
-
- Purpose: Provides a numeric value indicating the maximum size of a
- resource in octets that the server is willing to accept when a
- calendar object resource is stored in a calendar collection.
-
- Conformance: This property MAY be defined on any calendar
- collection. If defined, it MUST be protected and SHOULD NOT be
- returned by a PROPFIND DAV:allprop request (as defined in Section
- 12.14.1 of [RFC2518]).
-
- Description: The CALDAV:max-resource-size is used to specify a
- numeric value that represents the maximum size in octets that the
- server is willing to accept when a calendar object resource is
- stored in a calendar collection. Any attempt to store a calendar
- object resource exceeding this size MUST result in an error, with
- the CALDAV:max-resource-size precondition (Section 5.3.2.1) being
- violated. In the absence of this property, the client can assume
- that the server will allow storing a resource of any reasonable
- size.
-
- Definition:
-
-
- PCDATA value: a numeric value (positive integer)
-
-
-
-
-
- Example:
-
- 102400
-
-5.2.6. CALDAV:min-date-time Property
-
- Name: min-date-time
-
- Namespace: urn:ietf:params:xml:ns:caldav
-
- Purpose: Provides a DATE-TIME value indicating the earliest date and
- time (in UTC) that the server is willing to accept for any DATE or
- DATE-TIME value in a calendar object resource stored in a calendar
- collection.
-
- Conformance: This property MAY be defined on any calendar
- collection. If defined, it MUST be protected and SHOULD NOT be
- returned by a PROPFIND DAV:allprop request (as defined in Section
- 12.14.1 of [RFC2518]).
-
- Description: The CALDAV:min-date-time is used to specify an
- iCalendar DATE-TIME value in UTC that indicates the earliest
- inclusive date that the server is willing to accept for any
- explicit DATE or DATE-TIME value in a calendar object resource
- stored in a calendar collection. Any attempt to store a calendar
- object resource using a DATE or DATE-TIME value earlier than this
- value MUST result in an error, with the CALDAV:min-date-time
- precondition (Section 5.3.2.1) being violated. Note that servers
- MUST accept recurring components that specify instances beyond
- this limit, provided none of those instances have been overridden.
- In that case, the server MAY simply ignore those instances outside
- of the acceptable range when processing reports on the calendar
- object resource. In the absence of this property, the client can
- assume any valid iCalendar date may be used at least up to the
- CALDAV:max-date-time value, if that is defined.
-
- Definition:
-
-
- PCDATA value: an iCalendar format DATE-TIME value in UTC
-
- Example:
-
- 19000101T000000Z
-
-
-
-
-
-
-5.2.7. CALDAV:max-date-time Property
-
- Name: max-date-time
-
- Namespace: urn:ietf:params:xml:ns:caldav
-
- Purpose: Provides a DATE-TIME value indicating the latest date and
- time (in UTC) that the server is willing to accept for any DATE or
- DATE-TIME value in a calendar object resource stored in a calendar
- collection.
-
- Conformance: This property MAY be defined on any calendar
- collection. If defined, it MUST be protected and SHOULD NOT be
- returned by a PROPFIND DAV:allprop request (as defined in Section
- 12.14.1 of [RFC2518]).
-
- Description: The CALDAV:max-date-time is used to specify an
- iCalendar DATE-TIME value in UTC that indicates the inclusive
- latest date that the server is willing to accept for any date or
- time value in a calendar object resource stored in a calendar
- collection. Any attempt to store a calendar object resource using
- a DATE or DATE-TIME value later than this value MUST result in an
- error, with the CALDAV:max-date-time precondition
- (Section 5.3.2.1) being violated. Note that servers MUST accept
- recurring components that specify instances beyond this limit,
- provided none of those instances have been overridden. In that
- case, the server MAY simply ignore those instances outside of the
- acceptable range when processing reports on the calendar object
- resource. In the absence of this property, the client can assume
- any valid iCalendar date may be used at least down to the CALDAV:
- min-date-time value, if that is defined.
-
- Definition:
-
-
- PCDATA value: an iCalendar format DATE-TIME value in UTC
-
- Example:
-
- 20491231T235959Z
-
-
-
-
-
-
-
-
-
-
-
-5.2.8. CALDAV:max-instances Property
-
- Name: max-instances
-
- Namespace: urn:ietf:params:xml:ns:caldav
-
- Purpose: Provides a numeric value indicating the maximum number of
- recurrence instances that a calendar object resource stored in a
- calendar collection can generate.
-
- Conformance: This property MAY be defined on any calendar
- collection. If defined, it MUST be protected and SHOULD NOT be
- returned by a PROPFIND DAV:allprop request (as defined in Section
- 12.14.1 of [RFC2518]).
-
- Description: The CALDAV:max-instances is used to specify a numeric
- value that indicates the maximum number of recurrence instances
- that a calendar object resource stored in a calendar collection
- can generate. Any attempt to store a calendar object resource
- with a recurrence pattern that generates more instances than this
- value MUST result in an error, with the CALDAV:max-instances
- precondition (Section 5.3.2.1) being violated. In the absence of
- this property, the client can assume that the server has no limits
- on the number of recurrence instances it can handle or expand.
-
- Definition:
-
-
- PCDATA value: a numeric value (integer greater than zero)
-
- Example:
-
- 100
-
-5.2.9. CALDAV:max-attendees-per-instance Property
-
- Name: max-attendees-per-instance
-
- Namespace: urn:ietf:params:xml:ns:caldav
-
- Purpose: Provides a numeric value indicating the maximum number of
- ATTENDEE properties in any instance of a calendar object resource
- stored in a calendar collection.
-
- Conformance: This property MAY be defined on any calendar
- collection. If defined, it MUST be protected and SHOULD NOT be
-
-
-
-
-
- returned by a PROPFIND DAV:allprop request (as defined in Section
- 12.14.1 of [RFC2518]).
-
- Description: The CALDAV:max-attendees-per-instance is used to
- specify a numeric value that indicates the maximum number of
- iCalendar ATTENDEE properties on any one instance of a calendar
- object resource stored in a calendar collection. Any attempt to
- store a calendar object resource with more ATTENDEE properties per
- instance than this value MUST result in an error, with the CALDAV:
- max-attendees-per-instance precondition (Section 5.3.2.1) being
- violated. In the absence of this property, the client can assume
- that the server can handle any number of ATTENDEE properties in a
- calendar component.
-
- Definition:
-
-
- PCDATA value: a numeric value (integer greater than zero)
-
- Example:
-
- 25
-
-5.2.10. Additional Precondition for PROPPATCH
-
- This specification requires an additional Precondition for the
- PROPPATCH method. The precondition is:
-
- (CALDAV:valid-calendar-data): The time zone specified in CALDAV:
- calendar-timezone property MUST be a valid iCalendar object
- containing a single valid VTIMEZONE component.
-
-5.3. Creating Resources
-
- Calendar collections and calendar object resources may be created by
- either a CalDAV client or by the CalDAV server. This specification
- defines restrictions and a data model that both clients and servers
- MUST adhere to when manipulating such calendar data.
-
-5.3.1. MKCALENDAR Method
-
- An HTTP request using the MKCALENDAR method creates a new calendar
- collection resource. A server MAY restrict calendar collection
- creation to particular collections.
-
-
-
-
-
-
- Support for MKCALENDAR on the server is only RECOMMENDED and not
- REQUIRED because some calendar stores only support one calendar per
- user (or principal), and those are typically pre-created for each
- account. However, servers and clients are strongly encouraged to
- support MKCALENDAR whenever possible to allow users to create
- multiple calendar collections to help organize their data better.
-
- Clients SHOULD use the DAV:displayname property for a human-readable
- name of the calendar. Clients can either specify the value of the
- DAV:displayname property in the request body of the MKCALENDAR
- request, or alternatively issue a PROPPATCH request to change the
- DAV:displayname property to the appropriate value immediately after
- issuing the MKCALENDAR request. Clients SHOULD NOT set the DAV:
- displayname property to be the same as any other calendar collection
- at the same URI "level". When displaying calendar collections to
- users, clients SHOULD check the DAV:displayname property and use that
- value as the name of the calendar. In the event that the DAV:
- displayname property is empty, the client MAY use the last part of
- the calendar collection URI as the name; however, that path segment
- may be "opaque" and not represent any meaningful human-readable text.
-
- If a MKCALENDAR request fails, the server state preceding the request
- MUST be restored.
-
- Marshalling:
- If a request body is included, it MUST be a CALDAV:mkcalendar XML
- element. Instruction processing MUST occur in the order
- instructions are received (i.e., from top to bottom).
- Instructions MUST either all be executed or none executed. Thus,
- if any error occurs during processing, all executed instructions
- MUST be undone and a proper error result returned. Instruction
- processing details can be found in the definition of the DAV:set
- instruction in Section 12.13.2 of [RFC2518].
-
-
-
- If a response body for a successful request is included, it MUST
- be a CALDAV:mkcalendar-response XML element.
-
-
-
- The response MUST include a Cache-Control:no-cache header.
-
- Preconditions:
-
- (DAV:resource-must-be-null): A resource MUST NOT exist at the
- Request-URI;
-
-
-
-
-
- (CALDAV:calendar-collection-location-ok): The Request-URI MUST
- identify a location where a calendar collection can be created;
-
- (CALDAV:valid-calendar-data): The time zone specified in the
- CALDAV:calendar-timezone property MUST be a valid iCalendar object
- containing a single valid VTIMEZONE component;
-
- (DAV:needs-privilege): The DAV:bind privilege MUST be granted to
- the current user on the parent collection of the Request-URI.
-
- Postconditions:
-
- (CALDAV:initialize-calendar-collection): A new calendar collection
- exists at the Request-URI. The DAV:resourcetype of the calendar
- collection MUST contain both DAV:collection and CALDAV:calendar
- XML elements.
-
-5.3.1.1. Status Codes
-
- The following are examples of response codes one would expect to get
- in a response to a MKCALENDAR request. Note that this list is by no
- means exhaustive.
-
- 201 (Created) - The calendar collection resource was created in
- its entirety;
-
- 207 (Multi-Status) - The calendar collection resource was not
- created since one or more DAV:set instructions specified in the
- request body could not be processed successfully. The following
- are examples of response codes one would expect to be used in a
- 207 (Multi-Status) response in this situation:
-
- 403 (Forbidden) - The client, for reasons the server chooses
- not to specify, cannot alter one of the properties;
-
- 409 (Conflict) - The client has provided a value whose
- semantics are not appropriate for the property. This includes
- trying to set read-only properties;
-
- 424 (Failed Dependency) - The DAV:set instruction on the
- specified resource would have succeeded if it were not for the
- failure of another DAV:set instruction specified in the request
- body;
-
- 423 (Locked) - The specified resource is locked and the client
- either is not a lock owner or the lock type requires a lock
- token to be submitted and the client did not submit it; and
-
-
-
-
-
- 507 (Insufficient Storage) - The server did not have sufficient
- space to record the property;
-
- 403 (Forbidden) - This indicates at least one of two conditions:
- 1) the server does not allow the creation of calendar collections
- at the given location in its namespace, or 2) the parent
- collection of the Request-URI exists but cannot accept members;
-
- 409 (Conflict) - A collection cannot be made at the Request-URI
- until one or more intermediate collections have been created;
-
- 415 (Unsupported Media Type) - The server does not support the
- request type of the body; and
-
- 507 (Insufficient Storage) - The resource does not have sufficient
- space to record the state of the resource after the execution of
- this method.
-
-5.3.1.2. Example: Successful MKCALENDAR Request
-
- This example creates a calendar collection called /home/lisa/
- calendars/events/ on the server cal.example.com with specific values
- for the properties DAV:displayname, CALDAV:calendar-description,
- CALDAV:supported-calendar-component-set, and CALDAV:calendar-
- timezone.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- >> Request <<
-
- MKCALENDAR /home/lisa/calendars/events/ HTTP/1.1
- Host: cal.example.com
- Content-Type: application/xml; charset="utf-8"
- Content-Length: xxxx
-
-
-
-
-
- Lisa's Events
- Calendar restricted to events.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- >> Response <<
-
- HTTP/1.1 201 Created
- Cache-Control: no-cache
- Date: Sat, 11 Nov 2006 09:32:12 GMT
- Content-Length: 0
-
-5.3.2. Creating Calendar Object Resources
-
- Clients populate calendar collections with calendar object resources.
- The URL for each calendar object resource is entirely arbitrary and
- does not need to bear a specific relationship to the calendar object
- resource's iCalendar properties or other metadata. New calendar
- object resources MUST be created with a PUT request targeted at an
- unmapped URI. A PUT request targeted at a mapped URI updates an
- existing calendar object resource.
-
- When servers create new resources, it's not hard for the server to
- choose an unmapped URI. It's slightly tougher for clients, because a
- client might not want to examine all resources in the collection and
- might not want to lock the entire collection to ensure that a new
- resource isn't created with a name collision. However, there is an
- HTTP feature to mitigate this. If the client intends to create a new
- non-collection resource, such as a new VEVENT, the client SHOULD use
- the HTTP request header "If-None-Match: *" on the PUT request. The
- Request-URI on the PUT request MUST include the target collection,
- where the resource is to be created, plus the name of the resource in
- the last path segment. The "If-None-Match: *" request header ensures
- that the client will not inadvertently overwrite an existing resource
- if the last path segment turned out to already be used.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- >> Request <<
-
- PUT /home/lisa/calendars/events/qwue23489.ics HTTP/1.1
- If-None-Match: *
- Host: cal.example.com
- Content-Type: text/calendar
- Content-Length: xxxx
-
- BEGIN:VCALENDAR
- VERSION:2.0
- PRODID:-//Example Corp.//CalDAV Client//EN
- BEGIN:VEVENT
- UID:20010712T182145Z-123401@example.com
- DTSTAMP:20060712T182145Z
- DTSTART:20060714T170000Z
- DTEND:20060715T040000Z
- SUMMARY:Bastille Day Party
- END:VEVENT
- END:VCALENDAR
-
- >> Response <<
-
- HTTP/1.1 201 Created
- Content-Length: 0
- Date: Sat, 11 Nov 2006 09:32:12 GMT
- ETag: "123456789-000-111"
-
- The request to change an existing event is the same, but with a
- specific ETag in the "If-Match" header, rather than the "If-None-
- Match" header.
-
- As indicated in Section 3.10 of [RFC2445], the URL of calendar object
- resources containing (an arbitrary set of) calendaring and scheduling
- information may be suffixed by ".ics", and the URL of calendar object
- resources containing free or busy time information may be suffixed by
- ".ifb".
-
-5.3.2.1. Additional Preconditions for PUT, COPY, and MOVE
-
- This specification creates additional Preconditions for PUT, COPY,
- and MOVE methods. These preconditions apply when a PUT operation of
- a calendar object resource into a calendar collection occurs, or when
- a COPY or MOVE operation of a calendar object resource into a
- calendar collection occurs, or when a COPY or MOVE operation occurs
- on a calendar collection.
-
-
-
-
-
-
-
- The new preconditions are:
-
- (CALDAV:supported-calendar-data): The resource submitted in the
- PUT request, or targeted by a COPY or MOVE request, MUST be a
- supported media type (i.e., iCalendar) for calendar object
- resources;
-
- (CALDAV:valid-calendar-data): The resource submitted in the PUT
- request, or targeted by a COPY or MOVE request, MUST be valid data
- for the media type being specified (i.e., MUST contain valid
- iCalendar data);
-
- (CALDAV:valid-calendar-object-resource): The resource submitted in
- the PUT request, or targeted by a COPY or MOVE request, MUST obey
- all restrictions specified in Section 4.1 (e.g., calendar object
- resources MUST NOT contain more than one type of calendar
- component, calendar object resources MUST NOT specify the
- iCalendar METHOD property, etc.);
-
- (CALDAV:supported-calendar-component): The resource submitted in
- the PUT request, or targeted by a COPY or MOVE request, MUST
- contain a type of calendar component that is supported in the
- targeted calendar collection;
-
- (CALDAV:no-uid-conflict): The resource submitted in the PUT
- request, or targeted by a COPY or MOVE request, MUST NOT specify
- an iCalendar UID property value already in use in the targeted
- calendar collection or overwrite an existing calendar object
- resource with one that has a different UID property value.
- Servers SHOULD report the URL of the resource that is already
- making use of the same UID property value in the DAV:href element;
-
-
-
- (CALDAV:calendar-collection-location-ok): In a COPY or MOVE
- request, when the Request-URI is a calendar collection, the
- Destination-URI MUST identify a location where a calendar
- collection can be created;
-
- (CALDAV:max-resource-size): The resource submitted in the PUT
- request, or targeted by a COPY or MOVE request, MUST have an octet
- size less than or equal to the value of the CALDAV:max-resource-
- size property value (Section 5.2.5) on the calendar collection
- where the resource will be stored;
-
- (CALDAV:min-date-time): The resource submitted in the PUT request,
- or targeted by a COPY or MOVE request, MUST have all of its
- iCalendar DATE or DATE-TIME property values (for each recurring
-
-
-
-
- instance) greater than or equal to the value of the CALDAV:min-
- date-time property value (Section 5.2.6) on the calendar
- collection where the resource will be stored;
-
- (CALDAV:max-date-time): The resource submitted in the PUT request,
- or targeted by a COPY or MOVE request, MUST have all of its
- iCalendar DATE or DATE-TIME property values (for each recurring
- instance) less than the value of the CALDAV:max-date-time property
- value (Section 5.2.7) on the calendar collection where the
- resource will be stored;
-
- (CALDAV:max-instances): The resource submitted in the PUT request,
- or targeted by a COPY or MOVE request, MUST generate a number of
- recurring instances less than or equal to the value of the CALDAV:
- max-instances property value (Section 5.2.8) on the calendar
- collection where the resource will be stored;
-
- (CALDAV:max-attendees-per-instance): The resource submitted in the
- PUT request, or targeted by a COPY or MOVE request, MUST have a
- number of ATTENDEE properties on any one instance less than or
- equal to the value of the CALDAV:max-attendees-per-instance
- property value (Section 5.2.9) on the calendar collection where
- the resource will be stored;
-
-5.3.3. Non-Standard Components, Properties, and Parameters
-
- iCalendar provides a "standard mechanism for doing non-standard
- things". This extension support allows implementers to make use of
- non-standard components, properties, and parameters whose names are
- prefixed with the text "X-".
-
- Servers MUST support the use of non-standard components, properties,
- and parameters in calendar object resources stored via the PUT
- method.
-
- Servers may need to enforce rules for their own "private" components,
- properties, or parameters, so servers MAY reject any attempt by the
- client to change those or use values for those outside of any
- restrictions the server may have. Servers SHOULD ensure that any
- "private" components, properties, or parameters it uses follow the
- convention of including a vendor id in the "X-" name, as described in
- Section 4.2 of [RFC2445], e.g., "X-ABC-PRIVATE".
-
-5.3.4. Calendar Object Resource Entity Tag
-
- The DAV:getetag property MUST be defined and set to a strong entity
- tag on all calendar object resources.
-
-
-
-
-
- A response to a GET request targeted at a calendar object resource
- MUST contain an ETag response header field indicating the current
- value of the strong entity tag of the calendar object resource.
-
- Servers SHOULD return a strong entity tag (ETag header) in a PUT
- response when the stored calendar object resource is equivalent by
- octet equality to the calendar object resource submitted in the body
- of the PUT request. This allows clients to reliably use the returned
- strong entity tag for data synchronization purposes. For instance,
- the client can do a PROPFIND request on the stored calendar object
- resource and have the DAV:getetag property returned, and compare that
- value with the strong entity tag it received on the PUT response, and
- know that if they are equal, then the calendar object resource on the
- server has not been changed.
-
- In the case where the data stored by a server as a result of a PUT
- request is not equivalent by octet equality to the submitted calendar
- object resource, the behavior of the ETag response header is not
- specified here, with the exception that a strong entity tag MUST NOT
- be returned in the response. As a result, clients may need to
- retrieve the modified calendar object resource (and ETag) as a basis
- for further changes, rather than use the calendar object resource it
- had sent with the PUT request.
-
-6. Calendaring Access Control
-
-6.1. Calendaring Privilege
-
- CalDAV servers MUST support and adhere to the requirements of WebDAV
- ACL [RFC3744]. WebDAV ACL provides a framework for an extensible set
- of privileges that can be applied to WebDAV collections and ordinary
- resources. CalDAV servers MUST also support the calendaring
- privilege defined in this section.
-
-6.1.1. CALDAV:read-free-busy Privilege
-
- Calendar users often wish to allow other users to see their busy time
- information, without viewing the other details of the calendar
- components (e.g., location, summary, attendees). This allows a
- significant amount of privacy while still allowing other users to
- schedule meetings at times when the user is likely to be free.
-
- The CALDAV:read-free-busy privilege controls which calendar
- collections, regular collections, and calendar object resources are
- examined when a CALDAV:free-busy-query REPORT request is processed
- (see Section 7.10). This privilege can be granted on calendar
- collections, regular collections, or calendar object resources.
-
-
-
-
-
- Servers MUST support this privilege on all calendar collections,
- regular collections, and calendar object resources.
-
-
-
-
- The CALDAV:read-free-busy privilege MUST be aggregated in the DAV:
- read privilege. Servers MUST allow the CALDAV:read-free-busy to be
- granted without the DAV:read privilege being granted.
-
- Clients should note that when only the CALDAV:read-free-busy
- privilege has been granted on a resource, access to GET, HEAD,
- OPTIONS, and PROPFIND on the resource is not implied (those
- operations are governed by the DAV:read privilege).
-
-6.2. Additional Principal Property
-
- This section defines an additional property for WebDAV principal
- resources, as defined in [RFC3744].
-
-6.2.1. CALDAV:calendar-home-set Property
-
- Name: calendar-home-set
-
- Namespace: urn:ietf:params:xml:ns:caldav
-
- Purpose: Identifies the URL of any WebDAV collections that contain
- calendar collections owned by the associated principal resource.
-
- Conformance: This property SHOULD be defined on a principal
- resource. If defined, it MAY be protected and SHOULD NOT be
- returned by a PROPFIND DAV:allprop request (as defined in Section
- 12.14.1 of [RFC2518]).
-
- Description: The CALDAV:calendar-home-set property is meant to allow
- users to easily find the calendar collections owned by the
- principal. Typically, users will group all the calendar
- collections that they own under a common collection. This
- property specifies the URL of collections that are either calendar
- collections or ordinary collections that have child or descendant
- calendar collections owned by the principal.
-
- Definition:
-
-
-
-
-
-
-
-
-
- Example:
-
-
- http://cal.example.com/home/bernard/calendars/
-
-
-7. Calendaring Reports
-
- This section defines the reports that CalDAV servers MUST support on
- calendar collections and calendar object resources.
-
- CalDAV servers MUST advertise support for these reports on all
- calendar collections and calendar object resources with the DAV:
- supported-report-set property, defined in Section 3.1.5 of [RFC3253].
- CalDAV servers MAY also advertise support for these reports on
- ordinary collections.
-
- Some of these reports allow calendar data (from possibly multiple
- resources) to be returned.
-
-7.1. REPORT Method
-
- The REPORT method (defined in Section 3.6 of [RFC3253]) provides an
- extensible mechanism for obtaining information about one or more
- resources. Unlike the PROPFIND method, which returns the value of
- one or more named properties, the REPORT method can involve more
- complex processing. REPORT is valuable in cases where the server has
- access to all of the information needed to perform the complex
- request (such as a query), and where it would require multiple
- requests for the client to retrieve the information needed to perform
- the same request.
-
- CalDAV servers MUST support the DAV:expand-property REPORT defined in
- Section 3.8 of [RFC3253].
-
-7.2. Ordinary Collections
-
- Servers MAY support the reports defined in this document on ordinary
- collections (collections that are not calendar collections), in
- addition to calendar collections or calendar object resources. In
- computing responses to the reports on ordinary collections, servers
- MUST only consider calendar object resources contained in calendar
- collections that are targeted by the REPORT request, based on the
- value of the Depth request header.
-
-
-
-
-
-
-
-7.3. Date and Floating Time
-
- iCalendar provides a way to specify DATE and DATE-TIME values that
- are not bound to any time zone in particular, hereafter called
- "floating date" and "floating time", respectively. These values are
- used to represent the same day, hour, minute, and second value,
- regardless of which time zone is being observed. For instance, the
- DATE value "20051111", represents November 11, 2005 in no specific
- time zone, while the DATE-TIME value "20051111T111100" represents
- November 11, 2005, at 11:11 A.M. in no specific time zone.
-
- CalDAV servers may need to convert "floating date" and "floating
- time" values in date with UTC time values in the processing of
- calendaring REPORT requests.
-
- For the CALDAV:calendar-query REPORT, CalDAV servers MUST rely on the
- value of the CALDAV:timezone XML element, if specified as part of the
- request body, to perform the proper conversion of "floating date" and
- "floating time" values to date with UTC time values. If the CALDAV:
- timezone XML element is not specified in the request body, CalDAV
- servers MUST rely on the value of the CALDAV:calendar-timezone
- property, if defined, or else the CalDAV servers MAY rely on the time
- zone of their choice.
-
- For the CALDAV:free-busy-query REPORT, CalDAV servers MUST rely on
- the value of the CALDAV:calendar-timezone property, if defined, to
- compute the proper FREEBUSY time period value as date with UTC time
- for calendar components scheduled with "floating date" or "floating
- time". If the CALDAV:calendar-timezone property is not defined,
- CalDAV servers MAY rely on the time zone of their choice.
-
-7.4. Time Range Filtering
-
- Some of the reports defined in this section can include a time range
- filter that is used to restrict the set of calendar object resources
- returned to just those that overlap the specified time range. The
- time range filter can be applied to a calendar component as a whole,
- or to specific calendar component properties with DATE or DATE-TIME
- value types.
-
- To determine whether a calendar object resource matches the time
- range filter element, the start and end times for the targeted
- component or property are determined and then compared to the
- requested time range. If there is an overlap with the requested time
- range, then the calendar object resource matches the filter element.
- The rules defined in [RFC2445] for determining the actual start and
- end times of calendar components MUST be used, and these are fully
- enumerated in Section 9.9 of this document.
-
-
-
-
- When such time range filtering is used, special consideration must be
- given to recurring calendar components, such as VEVENT and VTODO.
- The server MUST expand recurring components to determine whether any
- recurrence instances overlap the specified time range. If one or
- more recurrence instances overlap the time range, then the calendar
- object resource matches the filter element.
-
-7.5. Searching Text: Collations
-
- Some of the reports defined in this section do text matches of
- character strings provided by the client and are compared to stored
- calendar data. Since iCalendar data is, by default, encoded in the
- UTF-8 charset and may include characters outside the US-ASCII charset
- range in some property and parameter values, there is a need to
- ensure that text matching follows well-defined rules.
-
- To deal with this, this specification makes use of the IANA Collation
- Registry defined in [RFC4790] to specify collations that may be used
- to carry out the text comparison operations with a well-defined rule.
-
- The comparisons used in CalDAV are all "substring" matches, as per
- [RFC4790], Section 4.2. Collations supported by the server MUST
- support "substring" match operations.
-
- CalDAV servers are REQUIRED to support the "i;ascii-casemap" and
- "i;octet" collations, as described in [RFC4790], and MAY support
- other collations.
-
- Servers MUST advertise the set of collations that they support via
- the CALDAV:supported-collation-set property defined on any resource
- that supports reports that use collations.
-
- Clients MUST only use collations from the list advertised by the
- server.
-
- In the absence of a collation explicitly specified by the client, or
- if the client specifies the "default" collation identifier (as
- defined in [RFC4790], Section 3.1), the server MUST default to using
- "i;ascii-casemap" as the collation.
-
- Wildcards (as defined in [RFC4790], Section 3.2) MUST NOT be used in
- the collation identifier.
-
- If the client chooses a collation not supported by the server, the
- server MUST respond with a CALDAV:supported-collation precondition
- error response.
-
-
-
-
-
-
-7.5.1. CALDAV:supported-collation-set Property
-
- Name: supported-collation-set
-
- Namespace: urn:ietf:params:xml:ns:caldav
-
- Purpose: Identifies the set of collations supported by the server
- for text matching operations.
-
- Conformance: This property MUST be defined on any resource that
- supports a report that does text matching. If defined, it MUST be
- protected and SHOULD NOT be returned by a PROPFIND DAV:allprop
- request (as defined in Section 12.14.1 of [RFC2518]).
-
- Description: The CALDAV:supported-collation-set property contains
- zero or more CALDAV:supported-collation elements, which specify
- the collection identifiers of the collations supported by the
- server.
-
- Definition:
-
-
-
-
-
- Example:
-
-
- i;ascii-casemap
- i;octet
-
-
-7.6. Partial Retrieval
-
- Some calendaring reports defined in this document allow partial
- retrieval of calendar object resources. A CalDAV client can specify
- what information to return in the body of a calendaring REPORT
- request.
-
- A CalDAV client can request particular WebDAV property values, all
- WebDAV property values, or a list of the names of the resource's
- WebDAV properties. A CalDAV client can also request calendar data to
- be returned and specify whether all calendar components and
- properties should be returned, or only particular ones. See CALDAV:
- calendar-data in Section 9.6.
-
-
-
-
-
-
- By default, the returned calendar data will include the component
- that defines the recurrence set, referred to as the "master
- component", as well as the components that define exceptions to the
- recurrence set, referred to as the "overridden components".
-
- A CalDAV client that is only interested in the recurrence instances
- that overlap a specified time range can request to receive only the
- "master component", along with the "overridden components" that
- impact the specified time range, and thus, limit the data returned by
- the server (see CALDAV:limit-recurrence-set in Section 9.6.6). An
- overridden component impacts a time range if its current start and
- end times overlap the time range, or if the original start and end
- times -- the ones that would have been used if the instance were not
- overridden -- overlap the time range, or if it affects other
- instances that overlap the time range.
-
- A CalDAV client with no support for recurrence properties (i.e.,
- EXDATE, EXRULE, RDATE, and RRULE) and possibly VTIMEZONE components,
- or a client unwilling to perform recurrence expansion because of
- limited processing capability, can request to receive only the
- recurrence instances that overlap a specified time range as separate
- calendar components that each define exactly one recurrence instance
- (see CALDAV:expand in Section 9.6.5.)
-
- Finally, in the case of VFREEBUSY components, a CalDAV client can
- request to receive only the FREEBUSY property values that overlap a
- specified time range (see CALDAV:limit-freebusy-set in
- Section 9.6.7.)
-
-7.7. Non-Standard Components, Properties, and Parameters
-
- Servers MUST support the use of non-standard component, property, or
- parameter names in the CALDAV:calendar-data XML element in
- calendaring REPORT requests to allow clients to request that non-
- standard components, properties, and parameters be returned in the
- calendar data provided in the response.
-
- Servers MAY support the use of non-standard component, property, or
- parameter names in the CALDAV:comp-filter, CALDAV:prop-filter, and
- CALDAV:param-filter XML elements specified in the CALDAV:filter XML
- element of calendaring REPORT requests.
-
- Servers MUST fail with the CALDAV:supported-filter precondition if a
- calendaring REPORT request uses a CALDAV:comp-filter, CALDAV:prop-
- filter, or CALDAV:param-filter XML element that makes reference to a
- non-standard component, property, or parameter name on which the
- server does not support queries.
-
-
-
-
-
-7.8. CALDAV:calendar-query REPORT
-
- The CALDAV:calendar-query REPORT performs a search for all calendar
- object resources that match a specified filter. The response of this
- report will contain all the WebDAV properties and calendar object
- resource data specified in the request. In the case of the CALDAV:
- calendar-data XML element, one can explicitly specify the calendar
- components and properties that should be returned in the calendar
- object resource data that matches the filter.
-
- The format of this report is modeled on the PROPFIND method. The
- request and response bodies of the CALDAV:calendar-query REPORT use
- XML elements that are also used by PROPFIND. In particular, the
- request can include XML elements to request WebDAV properties to be
- returned. When that occurs, the response should follow the same
- behavior as PROPFIND with respect to the DAV:multistatus response
- elements used to return specific property results. For instance, a
- request to retrieve the value of a property that does not exist is an
- error and MUST be noted with a response XML element that contains a
- 404 (Not Found) status value.
-
- Support for the CALDAV:calendar-query REPORT is REQUIRED.
-
- Marshalling:
-
- The request body MUST be a CALDAV:calendar-query XML element, as
- defined in Section 9.5.
-
- The request MAY include a Depth header. If no Depth header is
- included, Depth:0 is assumed.
-
- The response body for a successful request MUST be a DAV:
- multistatus XML element (i.e., the response uses the same format
- as the response for PROPFIND). In the case where there are no
- response elements, the returned DAV:multistatus XML element is
- empty.
-
- The response body for a successful CALDAV:calendar-query REPORT
- request MUST contain a DAV:response element for each iCalendar
- object that matched the search filter. Calendar data is being
- returned in the CALDAV:calendar-data XML element inside the DAV:
- propstat XML element.
-
- Preconditions:
-
- (CALDAV:supported-calendar-data): The attributes "content-type"
- and "version" of the CALDAV:calendar-data XML element (see
-
-
-
-
-
- Section 9.6) specify a media type supported by the server for
- calendar object resources.
-
- (CALDAV:valid-filter): The CALDAV:filter XML element (see
- Section 9.7) specified in the REPORT request MUST be valid. For
- instance, a CALDAV:filter cannot nest a
- element in a element, and a CALDAV:filter
- cannot nest a element in a
- element.
-
- (CALDAV:supported-filter): The CALDAV:comp-filter (see
- Section 9.7.1), CALDAV:prop-filter (see Section 9.7.2), and
- CALDAV:param-filter (see Section 9.7.3) XML elements used in the
- CALDAV:filter XML element (see Section 9.7) in the REPORT request
- only make reference to components, properties, and parameters for
- which queries are supported by the server, i.e., if the CALDAV:
- filter element attempts to reference an unsupported component,
- property, or parameter, this precondition is violated. Servers
- SHOULD report the CALDAV:comp-filter, CALDAV:prop-filter, or
- CALDAV:param-filter for which it does not provide support.
-
-
-
- (CALDAV:valid-calendar-data): The time zone specified in the
- REPORT request MUST be a valid iCalendar object containing a
- single valid VTIMEZONE component.
-
- (CALDAV:min-date-time): Any XML element specifying a range of time
- MUST have its start or end DATE or DATE-TIME values greater than
- or equal to the value of the CALDAV:min-date-time property value
- (Section 5.2.6) on the calendar collections being targeted by the
- REPORT request;
-
- (CALDAV:max-date-time): Any XML element specifying a range of time
- MUST have its start or end DATE or DATE-TIME values less than or
- equal to the value of the CALDAV:max-date-time property value
- (Section 5.2.7) on the calendar collections being targeted by the
- REPORT request;
-
- (CALDAV:supported-collation): Any XML attribute specifying a
- collation MUST specify a collation supported by the server as
- described in Section 7.5.
-
-
-
-
-
-
-
-
- Postconditions:
-
- (DAV:number-of-matches-within-limits): The number of matching
- calendar object resources must fall within server-specific,
- predefined limits. For example, this condition might be triggered
- if a search specification would cause the return of an extremely
- large number of responses.
-
-7.8.1. Example: Partial Retrieval of Events by Time Range
-
- In this example, the client requests the server to return specific
- components and properties of the VEVENT components that overlap the
- time range from January 4, 2006, at 00:00:00 A.M. UTC to January 5,
- 2006, at 00:00:00 A.M. UTC. In addition, the DAV:getetag property is
- also requested and returned as part of the response. Note that the
- first calendar object returned is a recurring event whose first
- instance lies outside the requested time range, but whose third
- instance does overlap the time range. Note that due to the CALDAV:
- calendar-data element restrictions, the DTSTAMP property in VEVENT
- components has not been returned, and the only property returned in
- the VCALENDAR object is VERSION.
-
- See Appendix B for the calendar data being targeted by this example.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- >> Request <<
-
- REPORT /bernard/work/ HTTP/1.1
- Host: cal.example.com
- Depth: 1
- Content-Type: application/xml; charset="utf-8"
- Content-Length: xxxx
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- >> Response <<
-
- HTTP/1.1 207 Multi-Status
- Date: Sat, 11 Nov 2006 09:32:12 GMT
- Content-Type: application/xml; charset="utf-8"
- Content-Length: xxxx
-
-
-
-
-
-
-
- http://cal.example.com/bernard/work/abcd2.ics
-
-
- "fffff-abcd2"
- BEGIN:VCALENDAR
- VERSION:2.0
- BEGIN:VTIMEZONE
- LAST-MODIFIED:20040110T032845Z
- TZID:US/Eastern
- BEGIN:DAYLIGHT
- DTSTART:20000404T020000
- RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
- TZNAME:EDT
- TZOFFSETFROM:-0500
- TZOFFSETTO:-0400
- END:DAYLIGHT
- BEGIN:STANDARD
- DTSTART:20001026T020000
- RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
- TZNAME:EST
- TZOFFSETFROM:-0400
- TZOFFSETTO:-0500
- END:STANDARD
- END:VTIMEZONE
- BEGIN:VEVENT
- DTSTART;TZID=US/Eastern:20060102T120000
- DURATION:PT1H
- RRULE:FREQ=DAILY;COUNT=5
- SUMMARY:Event #2
- UID:00959BC664CA650E933C892C@example.com
- END:VEVENT
- BEGIN:VEVENT
- DTSTART;TZID=US/Eastern:20060104T140000
- DURATION:PT1H
- RECURRENCE-ID;TZID=US/Eastern:20060104T120000
- SUMMARY:Event #2 bis
- UID:00959BC664CA650E933C892C@example.com
- END:VEVENT
- BEGIN:VEVENT
- DTSTART;TZID=US/Eastern:20060106T140000
- DURATION:PT1H
- RECURRENCE-ID;TZID=US/Eastern:20060106T120000
- SUMMARY:Event #2 bis bis
- UID:00959BC664CA650E933C892C@example.com
-
-
-
-
- END:VEVENT
- END:VCALENDAR
-
-
- HTTP/1.1 200 OK
-
-
-
- http://cal.example.com/bernard/work/abcd3.ics
-
-
- "fffff-abcd3"
- BEGIN:VCALENDAR
- VERSION:2.0
- PRODID:-//Example Corp.//CalDAV Client//EN
- BEGIN:VTIMEZONE
- LAST-MODIFIED:20040110T032845Z
- TZID:US/Eastern
- BEGIN:DAYLIGHT
- DTSTART:20000404T020000
- RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
- TZNAME:EDT
- TZOFFSETFROM:-0500
- TZOFFSETTO:-0400
- END:DAYLIGHT
- BEGIN:STANDARD
- DTSTART:20001026T020000
- RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
- TZNAME:EST
- TZOFFSETFROM:-0400
- TZOFFSETTO:-0500
- END:STANDARD
- END:VTIMEZONE
- BEGIN:VEVENT
- DTSTART;TZID=US/Eastern:20060104T100000
- DURATION:PT1H
- SUMMARY:Event #3
- UID:DC6C50A017428C5216A2F1CD@example.com
- END:VEVENT
- END:VCALENDAR
-
-
- HTTP/1.1 200 OK
-
-
-
-
-
-
-
-
-
-7.8.2. Example: Partial Retrieval of Recurring Events
-
- In this example, the client requests the server to return VEVENT
- components that overlap the time range from January 3, 2006, at 00:
- 00:00 A.M. UTC to January 5, 2006, at 00:00:00 A.M. UTC. Use of the
- CALDAV:limit-recurrence-set element causes the server to only return
- overridden recurrence components that overlap the time range
- specified in that element or that affect other instances that overlap
- the time range (e.g., in the case of a THISANDFUTURE behavior). In
- this example, the first overridden component in the matching resource
- is returned, but the second one is not.
-
- See Appendix B for the calendar data being targeted by this example.
-
- >> Request <<
-
- REPORT /bernard/work/ HTTP/1.1
- Host: cal.example.com
- Depth: 1
- Content-Type: application/xml; charset="utf-8"
- Content-Length: xxxx
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- >> Response <<
-
- HTTP/1.1 207 Multi-Status
- Date: Sat, 11 Nov 2006 09:32:12 GMT
- Content-Type: application/xml; charset="utf-8"
- Content-Length: xxxx
-
-
-
-
-
-
-
-
- http://cal.example.com/bernard/work/abcd2.ics
-
-
- "fffff-abcd2"
- BEGIN:VCALENDAR
- VERSION:2.0
- PRODID:-//Example Corp.//CalDAV Client//EN
- BEGIN:VTIMEZONE
- LAST-MODIFIED:20040110T032845Z
- TZID:US/Eastern
- BEGIN:DAYLIGHT
- DTSTART:20000404T020000
- RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
- TZNAME:EDT
- TZOFFSETFROM:-0500
- TZOFFSETTO:-0400
- END:DAYLIGHT
- BEGIN:STANDARD
- DTSTART:20001026T020000
- RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
- TZNAME:EST
- TZOFFSETFROM:-0400
- TZOFFSETTO:-0500
- END:STANDARD
- END:VTIMEZONE
- BEGIN:VEVENT
- DTSTAMP:20060206T001121Z
- DTSTART;TZID=US/Eastern:20060102T120000
- DURATION:PT1H
- RRULE:FREQ=DAILY;COUNT=5
- SUMMARY:Event #2
- UID:00959BC664CA650E933C892C@example.com
- END:VEVENT
- BEGIN:VEVENT
- DTSTAMP:20060206T001121Z
- DTSTART;TZID=US/Eastern:20060104T140000
- DURATION:PT1H
- RECURRENCE-ID;TZID=US/Eastern:20060104T120000
- SUMMARY:Event #2 bis
- UID:00959BC664CA650E933C892C@example.com
- END:VEVENT
- END:VCALENDAR
-
-
-
-
-
-
- HTTP/1.1 200 OK
-
-
-
- http://cal.example.com/bernard/work/abcd3.ics
-
-
- "fffff-abcd3"
- BEGIN:VCALENDAR
- VERSION:2.0
- PRODID:-//Example Corp.//CalDAV Client//EN
- BEGIN:VTIMEZONE
- LAST-MODIFIED:20040110T032845Z
- TZID:US/Eastern
- BEGIN:DAYLIGHT
- DTSTART:20000404T020000
- RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
- TZNAME:EDT
- TZOFFSETFROM:-0500
- TZOFFSETTO:-0400
- END:DAYLIGHT
- BEGIN:STANDARD
- DTSTART:20001026T020000
- RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
- TZNAME:EST
- TZOFFSETFROM:-0400
- TZOFFSETTO:-0500
- END:STANDARD
- END:VTIMEZONE
- BEGIN:VEVENT
- ATTENDEE;PARTSTAT=ACCEPTED;ROLE=CHAIR:mailto:cyrus@example.com
- ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:lisa@example.com
- DTSTAMP:20060206T001220Z
- DTSTART;TZID=US/Eastern:20060104T100000
- DURATION:PT1H
- LAST-MODIFIED:20060206T001330Z
- ORGANIZER:mailto:cyrus@example.com
- SEQUENCE:1
- STATUS:TENTATIVE
- SUMMARY:Event #3
- UID:DC6C50A017428C5216A2F1CD@example.com
- X-ABC-GUID:E1CX5Dr-0007ym-Hz@example.com
- END:VEVENT
- END:VCALENDAR
-
-
- HTTP/1.1 200 OK
-
-
-
-
-
-
-
-
-7.8.3. Example: Expanded Retrieval of Recurring Events
-
- In this example, the client requests the server to return VEVENT
- components that overlap the time range from January 2, 2006, at 00:
- 00:00 A.M. UTC to January 5, 2006, at 00:00:00 A.M. UTC and to return
- recurring calendar components expanded into individual recurrence
- instance calendar components. Use of the CALDAV:expand element
- causes the server to only return overridden recurrence instances that
- overlap the time range specified in that element.
-
- See Appendix B for the calendar data being targeted by this example.
-
- >> Request <<
-
- REPORT /bernard/work/ HTTP/1.1
- Host: cal.example.com
- Depth: 1
- Content-Type: application/xml; charset="utf-8"
- Content-Length: xxxx
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- >> Response <<
-
- HTTP/1.1 207 Multi-Status
- Date: Sat, 11 Nov 2006 09:32:12 GMT
- Content-Type: application/xml; charset="utf-8"
- Content-Length: xxxx
-
-
-
-
-
-
-
- http://cal.example.com/bernard/work/abcd2.ics
-
-
- "fffff-abcd2"
- BEGIN:VCALENDAR
- VERSION:2.0
- PRODID:-//Example Corp.//CalDAV Client//EN
- BEGIN:VEVENT
- DTSTAMP:20060206T001121Z
- DTSTART:20060103T170000
- DURATION:PT1H
- RECURRENCE-ID:20060103T170000
- SUMMARY:Event #2
- UID:00959BC664CA650E933C892C@example.com
- END:VEVENT
- BEGIN:VEVENT
- DTSTAMP:20060206T001121Z
- DTSTART:20060104T190000
- DURATION:PT1H
- RECURRENCE-ID:20060104T170000
- SUMMARY:Event #2 bis
- UID:00959BC664CA650E933C892C@example.com
- END:VEVENT
- END:VCALENDAR
-
-
- HTTP/1.1 200 OK
-
-
-
- http://cal.example.com/bernard/work/abcd3.ics
-
-
- "fffff-abcd3"
- BEGIN:VCALENDAR
- VERSION:2.0
- PRODID:-//Example Corp.//CalDAV Client//EN
- BEGIN:VEVENT
- ATTENDEE;PARTSTAT=ACCEPTED;ROLE=CHAIR:mailto:cyrus@example.com
- ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:lisa@example.com
- DTSTAMP:20060206T001220Z
- DTSTART:20060104T150000
- DURATION:PT1H
- LAST-MODIFIED:20060206T001330Z
-
-
-
-
- ORGANIZER:mailto:cyrus@example.com
- SEQUENCE:1
- STATUS:TENTATIVE
- SUMMARY:Event #3
- UID:DC6C50A017428C5216A2F1CD@example.com
- X-ABC-GUID:E1CX5Dr-0007ym-Hz@example.com
- END:VEVENT
- END:VCALENDAR
-
-
- HTTP/1.1 200 OK
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-7.8.4. Example: Partial Retrieval of Stored Free Busy Components
-
- In this example, the client requests the server to return the
- VFREEBUSY components that have free busy information that overlap the
- time range from January 2, 2006, at 00:00:00 A.M. UTC (inclusively)
- to January 3, 2006, at 00:00:00 A.M. UTC (exclusively). Use of the
- CALDAV:limit-freebusy-set element causes the server to only return
- the FREEBUSY property values that overlap the time range specified in
- that element. Note that this is not an example of discovering when
- the calendar owner is busy.
-
- See Appendix B for the calendar data being targeted by this example.
-
- >> Request <<
-
- REPORT /bernard/work/ HTTP/1.1
- Host: cal.example.com
- Depth: 1
- Content-Type: application/xml; charset="utf-8"
- Content-Length: xxxx
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- >> Response <<
-
- HTTP/1.1 207 Multi-Status
- Date: Sat, 11 Nov 2006 09:32:12 GMT
- Content-Type: application/xml; charset="utf-8"
- Content-Length: xxxx
-
-
-
-
- http://cal.example.com/bernard/work/abcd8.ics
-
-
- "fffff-abcd8"
- BEGIN:VCALENDAR
- VERSION:2.0
- PRODID:-//Example Corp.//CalDAV Client//EN
- BEGIN:VFREEBUSY
- ORGANIZER;CN="Bernard Desruisseaux":mailto:bernard@example.com
- UID:76ef34-54a3d2@example.com
- DTSTAMP:20050530T123421Z
- DTSTART:20060101T100000Z
- DTEND:20060108T100000Z
- FREEBUSY;FBTYPE=BUSY-TENTATIVE:20060102T100000Z/20060102T120000Z
- END:VFREEBUSY
- END:VCALENDAR
-
-
- HTTP/1.1 200 OK
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-7.8.5. Example: Retrieval of To-Dos by Alarm Time Range
-
- In this example, the client requests the server to return the VTODO
- components that have an alarm trigger scheduled in the specified time
- range.
-
- See Appendix B for the calendar data being targeted by this example.
-
- >> Request <<
-
- REPORT /bernard/work/ HTTP/1.1
- Host: cal.example.com
- Depth: 1
- Content-Type: application/xml; charset="utf-8"
- Content-Length: xxxx
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- >> Response <<
-
- HTTP/1.1 207 Multi-Status
- Date: Sat, 11 Nov 2006 09:32:12 GMT
- Content-Type: application/xml; charset="utf-8"
- Content-Length: xxxx
-
-
-
-
- http://cal.example.com/bernard/work/abcd4.ics
-
-
- "fffff-abcd4"
- BEGIN:VCALENDAR
- VERSION:2.0
- PRODID:-//Example Corp.//CalDAV Client//EN
- BEGIN:VTODO
- DTSTAMP:20060205T235300Z
- DUE;TZID=US/Eastern:20060106T120000
- LAST-MODIFIED:20060205T235308Z
- SEQUENCE:1
- STATUS:NEEDS-ACTION
- SUMMARY:Task #2
- UID:E10BA47467C5C69BB74E8720@example.com
- BEGIN:VALARM
- ACTION:AUDIO
- TRIGGER;RELATED=START:-PT10M
- END:VALARM
- END:VTODO
- END:VCALENDAR
-
-
- HTTP/1.1 200 OK
-
-
-
-
-7.8.6. Example: Retrieval of Event by UID
-
- In this example, the client requests the server to return the VEVENT
- component that has the UID property set to
- "DC6C50A017428C5216A2F1CD@example.com".
-
- See Appendix B for the calendar data being targeted by this example.
-
-
-
-
-
-
- >> Request <<
-
- REPORT /bernard/work/ HTTP/1.1
- Host: cal.example.com
- Depth: 1
- Content-Type: application/xml; charset="utf-8"
- Content-Length: xxxx
-
-
-
-
-
-
-
-
-
-
-
- DC6C50A017428C5216A2F1CD@example.com
-
-
-
-
-
-
- >> Response <<
-
- HTTP/1.1 207 Multi-Status
- Date: Sat, 11 Nov 2006 09:32:12 GMT
- Content-Type: application/xml; charset="utf-8"
- Content-Length: xxxx
-
-
-
-
- http://cal.example.com/bernard/work/abcd3.ics
-
-
- "fffff-abcd3"
- BEGIN:VCALENDAR
- VERSION:2.0
- PRODID:-//Example Corp.//CalDAV Client//EN
- BEGIN:VTIMEZONE
- LAST-MODIFIED:20040110T032845Z
- TZID:US/Eastern
- BEGIN:DAYLIGHT
-
-
-
-
- DTSTART:20000404T020000
- RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
- TZNAME:EDT
- TZOFFSETFROM:-0500
- TZOFFSETTO:-0400
- END:DAYLIGHT
- BEGIN:STANDARD
- DTSTART:20001026T020000
- RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
- TZNAME:EST
- TZOFFSETFROM:-0400
- TZOFFSETTO:-0500
- END:STANDARD
- END:VTIMEZONE
- BEGIN:VEVENT
- ATTENDEE;PARTSTAT=ACCEPTED;ROLE=CHAIR:mailto:cyrus@example.com
- ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:lisa@example.com
- DTSTAMP:20060206T001220Z
- DTSTART;TZID=US/Eastern:20060104T100000
- DURATION:PT1H
- LAST-MODIFIED:20060206T001330Z
- ORGANIZER:mailto:cyrus@example.com
- SEQUENCE:1
- STATUS:TENTATIVE
- SUMMARY:Event #3
- UID:DC6C50A017428C5216A2F1CD@example.com
- X-ABC-GUID:E1CX5Dr-0007ym-Hz@example.com
- END:VEVENT
- END:VCALENDAR
-
-
- HTTP/1.1 200 OK
-
-
-
-
-7.8.7. Example: Retrieval of Events by PARTSTAT
-
- In this example, the client requests the server to return the VEVENT
- components that have the ATTENDEE property with the value
- "mailto:lisa@example.com" and for which the PARTSTAT parameter is set
- to NEEDS-ACTION.
-
- See Appendix B for the calendar data being targeted by this example.
-
-
-
-
-
-
-
-
- >> Request <<
-
- REPORT /bernard/work/ HTTP/1.1
- Host: cal.example.com
- Depth: 1
- Content-Type: application/xml; charset="utf-8"
- Content-Length: xxxx
-
-
-
-
-
-
-
-
-
-
-
- mailto:lisa@example.com
-
- NEEDS-ACTION
-
-
-
-
-
-
-
- >> Response <<
-
- HTTP/1.1 207 Multi-Status
- Date: Sat, 11 Nov 2006 09:32:12 GMT
- Content-Type: application/xml; charset="utf-8"
- Content-Length: xxxx
-
-
-
-
- http://cal.example.com/bernard/work/abcd3.ics
-
-
- "fffff-abcd3"
- BEGIN:VCALENDAR
- VERSION:2.0
- PRODID:-//Example Corp.//CalDAV Client//EN
-
-
-
-
- BEGIN:VTIMEZONE
- LAST-MODIFIED:20040110T032845Z
- TZID:US/Eastern
- BEGIN:DAYLIGHT
- DTSTART:20000404T020000
- RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
- TZNAME:EDT
- TZOFFSETFROM:-0500
- TZOFFSETTO:-0400
- END:DAYLIGHT
- BEGIN:STANDARD
- DTSTART:20001026T020000
- RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
- TZNAME:EST
- TZOFFSETFROM:-0400
- TZOFFSETTO:-0500
- END:STANDARD
- END:VTIMEZONE
- BEGIN:VEVENT
- ATTENDEE;PARTSTAT=ACCEPTED;ROLE=CHAIR:mailto:cyrus@example.com
- ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:lisa@example.com
- DTSTAMP:20060206T001220Z
- DTSTART;TZID=US/Eastern:20060104T100000
- DURATION:PT1H
- LAST-MODIFIED:20060206T001330Z
- ORGANIZER:mailto:cyrus@example.com
- SEQUENCE:1
- STATUS:TENTATIVE
- SUMMARY:Event #3
- UID:DC6C50A017428C5216A2F1CD@example.com
- X-ABC-GUID:E1CX5Dr-0007ym-Hz@example.com
- END:VEVENT
- END:VCALENDAR
-
-
- HTTP/1.1 200 OK
-
-
-
-
-7.8.8. Example: Retrieval of Events Only
-
- In this example, the client requests the server to return all VEVENT
- components.
-
- See Appendix B for the calendar data being targeted by this example.
-
-
-
-
-
-
- >> Request <<
-
- REPORT /bernard/work/ HTTP/1.1
- Host: cal.example.com
- Depth: 1
- Content-Type: application/xml; charset="utf-8"
- Content-Length: xxxx
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- >> Response <<
-
- HTTP/1.1 207 Multi-Status
- Date: Sat, 11 Nov 2006 09:32:12 GMT
- Content-Type: application/xml; charset="utf-8"
- Content-Length: xxxx
-
-
-
-
- http://cal.example.com/bernard/work/abcd1.ics
-
-
- "fffff-abcd1"
- BEGIN:VCALENDAR
- VERSION:2.0
- PRODID:-//Example Corp.//CalDAV Client//EN
- BEGIN:VTIMEZONE
- LAST-MODIFIED:20040110T032845Z
- TZID:US/Eastern
- BEGIN:DAYLIGHT
- DTSTART:20000404T020000
- RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
- TZNAME:EDT
- TZOFFSETFROM:-0500
- TZOFFSETTO:-0400
-
-
-
-
- END:DAYLIGHT
- BEGIN:STANDARD
- DTSTART:20001026T020000
- RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
- TZNAME:EST
- TZOFFSETFROM:-0400
- TZOFFSETTO:-0500
- END:STANDARD
- END:VTIMEZONE
- BEGIN:VEVENT
- DTSTAMP:20060206T001102Z
- DTSTART;TZID=US/Eastern:20060102T100000
- DURATION:PT1H
- SUMMARY:Event #1
- Description:Go Steelers!
- UID:74855313FA803DA593CD579A@example.com
- END:VEVENT
- END:VCALENDAR
-
-
- HTTP/1.1 200 OK
-
-
-
- http://cal.example.com/bernard/work/abcd2.ics
-
-
- "fffff-abcd2"
- BEGIN:VCALENDAR
- VERSION:2.0
- PRODID:-//Example Corp.//CalDAV Client//EN
- BEGIN:VTIMEZONE
- LAST-MODIFIED:20040110T032845Z
- TZID:US/Eastern
- BEGIN:DAYLIGHT
- DTSTART:20000404T020000
- RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
- TZNAME:EDT
- TZOFFSETFROM:-0500
- TZOFFSETTO:-0400
- END:DAYLIGHT
- BEGIN:STANDARD
- DTSTART:20001026T020000
- RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
- TZNAME:EST
- TZOFFSETFROM:-0400
- TZOFFSETTO:-0500
- END:STANDARD
-
-
-
-
- END:VTIMEZONE
- BEGIN:VEVENT
- DTSTAMP:20060206T001121Z
- DTSTART;TZID=US/Eastern:20060102T120000
- DURATION:PT1H
- RRULE:FREQ=DAILY;COUNT=5
- SUMMARY:Event #2
- UID:00959BC664CA650E933C892C@example.com
- END:VEVENT
- BEGIN:VEVENT
- DTSTAMP:20060206T001121Z
- DTSTART;TZID=US/Eastern:20060104T140000
- DURATION:PT1H
- RECURRENCE-ID;TZID=US/Eastern:20060104T120000
- SUMMARY:Event #2 bis
- UID:00959BC664CA650E933C892C@example.com
- END:VEVENT
- BEGIN:VEVENT
- DTSTAMP:20060206T001121Z
- DTSTART;TZID=US/Eastern:20060106T140000
- DURATION:PT1H
- RECURRENCE-ID;TZID=US/Eastern:20060106T120000
- SUMMARY:Event #2 bis bis
- UID:00959BC664CA650E933C892C@example.com
- END:VEVENT
- END:VCALENDAR
-
-
- HTTP/1.1 200 OK
-
-
-
- http://cal.example.com/bernard/work/abcd3.ics
-
-
- "fffff-abcd3"
- BEGIN:VCALENDAR
- VERSION:2.0
- PRODID:-//Example Corp.//CalDAV Client//EN
- BEGIN:VTIMEZONE
- LAST-MODIFIED:20040110T032845Z
- TZID:US/Eastern
- BEGIN:DAYLIGHT
- DTSTART:20000404T020000
- RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
- TZNAME:EDT
- TZOFFSETFROM:-0500
- TZOFFSETTO:-0400
-
-
-
-
- END:DAYLIGHT
- BEGIN:STANDARD
- DTSTART:20001026T020000
- RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
- TZNAME:EST
- TZOFFSETFROM:-0400
- TZOFFSETTO:-0500
- END:STANDARD
- END:VTIMEZONE
- BEGIN:VEVENT
- ATTENDEE;PARTSTAT=ACCEPTED;ROLE=CHAIR:mailto:cyrus@example.com
- ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:lisa@example.com
- DTSTAMP:20060206T001220Z
- DTSTART;TZID=US/Eastern:20060104T100000
- DURATION:PT1H
- LAST-MODIFIED:20060206T001330Z
- ORGANIZER:mailto:cyrus@example.com
- SEQUENCE:1
- STATUS:TENTATIVE
- SUMMARY:Event #3
- UID:DC6C50A017428C5216A2F1CD@example.com
- X-ABC-GUID:E1CX5Dr-0007ym-Hz@example.com
- END:VEVENT
- END:VCALENDAR
-
-
- HTTP/1.1 200 OK
-
-
-
-
-7.8.9. Example: Retrieval of All Pending To-Dos
-
- In this example, the client requests the server to return all VTODO
- components that do not include a COMPLETED property and do not have a
- STATUS property value matching CANCELLED, i.e., VTODOs that still
- need to be worked on.
-
- See Appendix B for the calendar data being targeted by this example.
-
-
-
-
-
-
-
-
-
-
-
-
-
- >> Request <<
-
- REPORT /bernard/work/ HTTP/1.1
- Host: cal.example.com
- Depth: 1
- Content-Type: application/xml; charset="utf-8"
- Content-Length: xxxx
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- CANCELLED
-
-
-
-
-
-
- >> Response <<
-
- HTTP/1.1 207 Multi-Status
- Date: Sat, 11 Nov 2006 09:32:12 GMT
- Content-Type: application/xml; charset="utf-8"
- Content-Length: xxxx
-
-
-
-
- http://cal.example.com/bernard/work/abcd4.ics
-
-
- "fffff-abcd4"
- BEGIN:VCALENDAR
- VERSION:2.0
- PRODID:-//Example Corp.//CalDAV Client//EN
- BEGIN:VTODO
-
-
-
-
- DTSTAMP:20060205T235335Z
- DUE;VALUE=DATE:20060104
- STATUS:NEEDS-ACTION
- SUMMARY:Task #1
- UID:DDDEEB7915FA61233B861457@example.com
- BEGIN:VALARM
- ACTION:AUDIO
- TRIGGER;RELATED=START:-PT10M
- END:VALARM
- END:VTODO
- END:VCALENDAR
-
-
- HTTP/1.1 200 OK
-
-
-
-
- http://cal.example.com/bernard/work/abcd5.ics
-
-
- "fffff-abcd5"
- BEGIN:VCALENDAR
- VERSION:2.0
- PRODID:-//Example Corp.//CalDAV Client//EN
- BEGIN:VTODO
- DTSTAMP:20060205T235300Z
- DUE;VALUE=DATE:20060106
- LAST-MODIFIED:20060205T235308Z
- SEQUENCE:1
- STATUS:NEEDS-ACTION
- SUMMARY:Task #2
- UID:E10BA47467C5C69BB74E8720@example.com
- BEGIN:VALARM
- ACTION:AUDIO
- TRIGGER;RELATED=START:-PT10M
- END:VALARM
- END:VTODO
- END:VCALENDAR
-
-
- HTTP/1.1 200 OK
-
-
-
-
-
-
-
-
-
-
-7.8.10. Example: Attempt to Query Unsupported Property
-
- In this example, the client requests the server to return all VEVENT
- components that include an X-ABC-GUID property with a value matching
- "ABC". However, the server does not support querying that non-
- standard property, and instead returns an error response.
-
- See Appendix B for the calendar data being targeted by this example.
-
- >> Request <<
-
- REPORT /bernard/work/ HTTP/1.1
- Host: cal.example.com
- Depth: 1
- Content-Type: application/xml; charset="utf-8"
- Content-Length: xxxx
-
-
-
-
-
-
-
-
-
-
-
- ABC
-
-
-
-
-
-
- >> Response <<
-
- HTTP/1.1 403 Forbidden
- Date: Sat, 11 Nov 2005 09:32:12 GMT
- Content-Type: application/xml; charset="utf-8"
- Content-Length: xxxx
-
-
-
-
-
-
-
-
-
-
-
-
-7.9. CALDAV:calendar-multiget REPORT
-
- The CALDAV:calendar-multiget REPORT is used to retrieve specific
- calendar object resources from within a collection, if the Request-
- URI is a collection, or to retrieve a specific calendar object
- resource, if the Request-URI is a calendar object resource. This
- report is similar to the CALDAV:calendar-query REPORT (see
- Section 7.8), except that it takes a list of DAV:href elements,
- instead of a CALDAV:filter element, to determine which calendar
- object resources to return.
-
- Support for the CALDAV:calendar-multiget REPORT is REQUIRED.
-
- Marshalling:
-
- The request body MUST be a CALDAV:calendar-multiget XML element
- (see Section 9.10). If the Request-URI is a collection resource,
- then the DAV:href elements MUST refer to calendar object resources
- within that collection, and they MAY refer to calendar object
- resources at any depth within the collection. As a result, the
- "Depth" header MUST be ignored by the server and SHOULD NOT be
- sent by the client. If the Request-URI refers to a non-collection
- resource, then there MUST be a single DAV:href element that is
- equivalent to the Request-URI.
-
- The response body for a successful request MUST be a DAV:
- multistatus XML element.
-
- The response body for a successful CALDAV:calendar-multiget REPORT
- request MUST contain a DAV:response element for each calendar
- object resource referenced by the provided set of DAV:href
- elements. Calendar data is being returned in the CALDAV:calendar-
- data element inside the DAV:prop element.
-
- In the case of an error accessing any of the provided DAV:href
- resources, the server MUST return the appropriate error status
- code in the DAV:status element of the corresponding DAV:response
- element.
-
- Preconditions:
-
- (CALDAV:supported-calendar-data): The attributes "content-type"
- and "version" of the CALDAV:calendar-data XML elements (see
- Section 9.6) specify a media type supported by the server for
- calendar object resources.
-
- (CALDAV:min-date-time): Any XML element specifying a range of time
- MUST have its start or end DATE or DATE-TIME values greater than
-
-
-
-
- or equal to the value of the CALDAV:min-date-time property value
- (Section 5.2.6) on the calendar collections being targeted by the
- REPORT request;
-
- (CALDAV:max-date-time): Any XML element specifying a range of time
- MUST have its start or end DATE or DATE-TIME values less than or
- equal to the value of the CALDAV:max-date-time property value
- (Section 5.2.7) on the calendar collections being targeted by the
- REPORT request;
-
- Postconditions:
-
- None.
-
-7.9.1. Example: Successful CALDAV:calendar-multiget REPORT
-
- In this example, the client requests the server to return specific
- properties of the VEVENT components referenced by specific URIs. In
- addition, the DAV:getetag property is also requested and returned as
- part of the response. Note that in this example, the resource at
- http://cal.example.com/bernard/work/mtg1.ics does not exist,
- resulting in an error status response.
-
- See Appendix B for the calendar data being targeted by this example.
-
- >> Request <<
-
- REPORT /bernard/work/ HTTP/1.1
- Host: cal.example.com
- Content-Type: application/xml; charset="utf-8"
- Content-Length: xxxx
-
-
-
-
-
-
-
- /bernard/work/abcd1.ics
- /bernard/work/mtg1.ics
-
-
- >> Response <<
-
- HTTP/1.1 207 Multi-Status
- Date: Sat, 11 Nov 2006 09:32:12 GMT
- Content-Type: application/xml; charset="utf-8"
-
-
-
-
- Content-Length: xxxx
-
-
-
-
- http://cal.example.com/bernard/work/abcd1.ics
-
-
- "fffff-abcd1"
- BEGIN:VCALENDAR
- VERSION:2.0
- PRODID:-//Example Corp.//CalDAV Client//EN
- BEGIN:VTIMEZONE
- LAST-MODIFIED:20040110T032845Z
- TZID:US/Eastern
- BEGIN:DAYLIGHT
- DTSTART:20000404T020000
- RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
- TZNAME:EDT
- TZOFFSETFROM:-0500
- TZOFFSETTO:-0400
- END:DAYLIGHT
- BEGIN:STANDARD
- DTSTART:20001026T020000
- RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
- TZNAME:EST
- TZOFFSETFROM:-0400
- TZOFFSETTO:-0500
- END:STANDARD
- END:VTIMEZONE
- BEGIN:VEVENT
- DTSTAMP:20060206T001102Z
- DTSTART;TZID=US/Eastern:20060102T100000
- DURATION:PT1H
- SUMMARY:Event #1
- Description:Go Steelers!
- UID:74855313FA803DA593CD579A@example.com
- END:VEVENT
- END:VCALENDAR
-
-
- HTTP/1.1 200 OK
-
-
-
- http://cal.example.com/bernard/work/mtg1.ics
- HTTP/1.1 404 Not Found
-
-
-
-
-
-
-
-7.10. CALDAV:free-busy-query REPORT
-
- The CALDAV:free-busy-query REPORT generates a VFREEBUSY component
- containing free busy information for all the calendar object
- resources targeted by the request and that have the CALDAV:read-free-
- busy or DAV:read privilege granted to the current user.
-
- Only VEVENT components without a TRANSP property or with the TRANSP
- property set to OPAQUE, and VFREEBUSY components SHOULD be considered
- in generating the free busy time information.
-
- In the case of VEVENT components, the free or busy time type (FBTYPE)
- of the FREEBUSY properties in the returned VFREEBUSY component SHOULD
- be derived from the value of the TRANSP and STATUS properties, as
- outlined in the table below:
-
- +---------------------------++------------------+
- | VEVENT || VFREEBUSY |
- +-------------+-------------++------------------+
- | TRANSP | STATUS || FBTYPE |
- +=============+=============++==================+
- | | CONFIRMED || BUSY |
- | | (default) || |
- | OPAQUE +-------------++------------------+
- | (default) | CANCELLED || FREE |
- | +-------------++------------------+
- | | TENTATIVE || BUSY-TENTATIVE |
- | +-------------++------------------+
- | | x-name || BUSY or |
- | | || x-name |
- +-------------+-------------++------------------+
- | | CONFIRMED || |
- | TRANSPARENT | CANCELLED || FREE |
- | | TENTATIVE || |
- | | x-name || |
- +-------------+-------------++------------------+
-
- Duplicate busy time periods with the same FBTYPE parameter value
- SHOULD NOT be specified in the returned VFREEBUSY component. Servers
- SHOULD coalesce consecutive or overlapping busy time periods of the
- same type. Busy time periods with different FBTYPE parameter values
- MAY overlap.
-
- Support for the CALDAV:free-busy-query REPORT is REQUIRED.
-
-
-
-
-
- Marshalling:
-
- The request body MUST be a CALDAV:free-busy-query XML element (see
- Section 9.11), which MUST contain exactly one CALDAV:time-range
- XML element, as defined in Section 9.9.
-
- The request MAY include a Depth header. If no Depth header is
- included, Depth:0 is assumed.
-
- The response body for a successful request MUST be an iCalendar
- object that contains exactly one VFREEBUSY component that
- describes the busy time intervals for the calendar object
- resources containing VEVENT, or VFREEBUSY components that satisfy
- the Depth value and for which the current user is at least granted
- the CALDAV:read-free-busy privilege. If no calendar object
- resources are found to satisfy these conditions, a VFREEBUSY
- component with no FREEBUSY property MUST be returned. This report
- only returns busy time information. Free time information can be
- inferred from the returned busy time information.
-
- If the current user is not granted the CALDAV:read-free-busy or
- DAV:read privileges on the Request-URI, the CALDAV:free-busy-query
- REPORT request MUST fail and return a 404 (Not Found) status
- value. This restriction will prevent users from discovering URLs
- of resources for which they are only granted the CALDAV:read-free-
- busy privilege.
-
- The CALDAV:free-busy-query REPORT request can only be run against
- a collection (either a regular collection or a calendar
- collection). An attempt to run the report on a calendar object
- resource MUST fail and return a 403 (Forbidden) status value.
-
- Preconditions:
-
- None.
-
- Postconditions:
-
- (DAV:number-of-matches-within-limits): The number of matching
- calendar object resources must fall within server-specific,
- predefined limits. For example, this postcondition might fail if
- the specified CALDAV:time-range would cause an extremely large
- number of calendar object resources to be considered in computing
- the response.
-
-
-
-
-
-
-
-
-7.10.1. Example: Successful CALDAV:free-busy-query REPORT
-
- In this example, the client requests the server to return free busy
- information on the calendar collection /bernard/work/, between 9:00
- A.M. and 5:00 P.M. EST (2:00 P.M. and 10:00 P.M. UTC) on the January
- 4, 2006. The server responds, indicating two busy time intervals of
- one hour, one of which is tentative.
-
- See Appendix B for the calendar data being targeted by this example.
-
- >> Request <<
-
- REPORT /bernard/work/ HTTP/1.1
- Host: cal.example.com
- Depth: 1
- Content-Type: application/xml; charset="utf-8"
- Content-Length: xxxx
-
-
-
-
-
-
- >> Response <<
-
- HTTP/1.1 200 OK
- Date: Sat, 11 Nov 2006 09:32:12 GMT
- Content-Type: text/calendar
- Content-Length: xxxx
-
- BEGIN:VCALENDAR
- VERSION:2.0
- PRODID:-//Example Corp.//CalDAV Server//EN
- BEGIN:VFREEBUSY
- DTSTAMP:20050125T090000Z
- DTSTART:20060104T140000Z
- DTEND:20060105T220000Z
- FREEBUSY;FBTYPE=BUSY-TENTATIVE:20060104T150000Z/PT1H
- FREEBUSY:20060104T190000Z/PT1H
- END:VFREEBUSY
- END:VCALENDAR
-
-
-
-
-
-
-
-
-
-
-8. Guidelines
-
-8.1. Client-to-Client Interoperability
-
- There are a number of actions clients can take that will be legal
- (the server will not return errors), but that can degrade
- interoperability with other client implementations accessing the same
- data. For example, a recurrence rule could be replaced with a set of
- recurrence dates, a single recurring event could be replaced with a
- set of independent resources to represent each recurrence, or the
- start/end time values can be translated from the original time zone
- to another time zone. Although this advice amounts to iCalendar
- interoperability best practices and is not limited only to CalDAV
- usage, interoperability problems are likely to be more evident in
- CalDAV use cases.
-
-8.2. Synchronization Operations
-
- WebDAV already provides functionality required to synchronize a
- collection or set of collections, to make changes offline, and
- provides a simple way to resolve conflicts when reconnected. ETags
- are the key to making this work, but these are not required of all
- WebDAV servers. Since offline functionality is more important to
- calendar applications than to some other WebDAV applications, CalDAV
- servers MUST support ETags, as specified in Section 5.3.4.
-
-8.2.1. Use of Reports
-
-8.2.1.1. Restrict the Time Range
-
- The reports provided in CalDAV can be used by clients to optimize
- their performance in terms of network bandwidth usage and resource
- consumption on the local client machine. Both are certainly major
- considerations for mobile or handheld devices with limited capacity,
- but they are also relevant to desktop client applications in cases
- where the calendar collections contain large amounts of data.
-
- Typically, clients present calendar data to users in views that span
- a finite time interval, so whenever possible, clients should only
- retrieve calendar components from the server using CALDAV:calendar-
- query REPORT, combined with a CALDAV:time-range element, to limit the
- set of returned components to just those needed to populate the
- current view.
-
-
-
-
-
-
-
-
-
-8.2.1.2. Synchronize by Time Range
-
- Typically in a calendar, historical data (events, to-dos, etc. that
- have completed prior to the current date) do not change, though they
- may be deleted. As a result, a client can speed up the
- synchronization process by only considering data for the present time
- and the future up to a reasonable limit (e.g., one week, one month).
- If the user then tries to examine a portion of the calendar outside
- the range that has been synchronized, the client can perform another
- synchronization operation on the new time interval being examined.
- This "just-in-time" synchronization can minimize bandwidth for common
- user interaction behaviors.
-
-8.2.1.3. Synchronization Process
-
- If a client wants to support calendar data synchronization, as
- opposed to downloading calendar data each time it is needed, the
- client needs to cache the calendar object resource's URI and ETag,
- along with the actual calendar data. While the URI remains static
- for the lifetime of the calendar object resource, the ETag will
- change with each successive change to the calendar object resource.
- Thus, to synchronize a local data cache with the server, the client
- can first fetch the URI/ETag pairs for the time interval being
- considered, and compare those results with the cached data. Any
- cached component whose ETag differs from that on the server needs to
- be refreshed.
-
- In order to properly detect the changes between the server and client
- data, the client will need to keep a record of which calendar object
- resources have been created, changed, or deleted since the last
- synchronization operation so that it can reconcile those changes with
- the data on the server.
-
- Here's an example of how to do that:
-
- The client issues a CALDAV:calendar-query REPORT request for a
- specific time range and asks for only the DAV:getetag property to be
- returned:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- REPORT /bernard/work/ HTTP/1.1
- Host: cal.example.com
- Depth: 1
- Content-Type: application/xml; charset="utf-8"
- Content-Length: xxxx
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- The client then uses the results to determine which calendar object
- resources have changed, been created, or deleted on the server, and
- how those relate to locally cached calendar object resources that may
- have changed, been created, or deleted. If the client determines
- that there are calendar object resources on the server that need to
- be fetched, the client issues a CALDAV:calendar-multiget REPORT
- request to fetch its calendar data:
-
- REPORT /bernard/work/ HTTP/1.1
- Host: cal.example.com
- Content-Type: application/xml; charset="utf-8"
- Content-Length: xxxx
-
-
-
-
-
-
-
- /bernard/work/abcd1.ics
- /bernard/work/mtg1.ics
-
-
-
-
-
-
-
-
-8.2.2. Restrict the Properties Returned
-
- A client may not need all the calendar properties of a calendar
- object resource when presenting information to the user. Since some
- calendar property values can be large (e.g., ATTACH or ATTENDEE), a
- client can choose to restrict the calendar properties to be returned
- in a calendaring REPORT request to those it knows it will use.
-
- However, if a client needs to make a change to a calendar object
- resource, it can only change the entire calendar object resource via
- a PUT request. There is currently no way to incrementally make a
- change to a set of calendar properties of a calendar object resource.
- As a result, the client will have to get the entire calendar object
- resource that is being changed.
-
-8.3. Use of Locking
-
- WebDAV locks can be used to prevent two clients that are modifying
- the same resource from either overwriting each others' changes
- (though that problem can also be solved by using ETags) or wasting
- time making changes that will conflict with another set of changes.
- In a multi-user calendar system, an interactive calendar client could
- lock an event while the user is editing the event, and unlock the
- event when the user finishes or cancels. Locks can also be used to
- prevent changes while data is being reorganized. For example, a
- calendar client might lock two calendar collections prior to moving a
- bunch of calendar resources from one to another.
-
- Clients are responsible for requesting a lock timeout period that is
- appropriate to the use case. When the user explicitly decides to
- reserve a resource and prevent other changes, a long timeout might be
- appropriate, but in cases where the client automatically decides to
- lock the resource, the timeout should be short (and the client can
- always refresh the lock should it need to). A short lock timeout
- means that if the client is unable to remove the lock, the other
- calendar users aren't prevented from making changes.
-
-8.4. Finding Calendars
-
- Much of the time, a calendar client (or agent) will discover a new
- calendar's location by being provided directly with the URL. For
- example, a user will type his or her own calendar location into
- client configuration information or copy and paste a URL from email
- into the calendar application. The client need only confirm that the
- URL points to a resource that is a calendar collection. The client
- may also be able to browse WebDAV collections to find calendar
- collections.
-
-
-
-
-
- The choice of HTTP URLs means that calendar object resources are
- backward compatible with existing software, but does have the
- disadvantage that existing software does not usually know to look at
- the OPTIONS response to that URL to determine what can be done with
- it. This is somewhat of a barrier for WebDAV usage as well as with
- CalDAV usage. This specification does not offer a way through this
- other than making the information available in the OPTIONS response
- should this be requested.
-
- For calendar sharing and scheduling use cases, one might wish to find
- the calendar belonging to another user. If the other user has a
- calendar in the same repository, that calendar can be found by using
- the principal namespace required by WebDAV ACL support. For other
- cases, the authors have no universal solution, but implementers can
- consider whether to use vCard [RFC2426] or LDAP [RFC4511] standards
- together with calendar attributes [RFC2739].
-
- Because CalDAV requires servers to support WebDAV ACL [RFC3744],
- including principal namespaces, and with the addition of the CALDAV:
- calendar-home-set property, there are a couple options for CalDAV
- clients to find one's own calendar or another user's calendar.
-
- In this case, a DAV:principal-match REPORT is used to find a named
- property (the CALDAV:calendar-home-set) on the Principal-URL of the
- current user. Using this, a WebDAV client can learn "who am I" and
- "where are my calendars". The REPORT request body looks like this:
-
-
-
-
-
-
-
-
-
- To find other users' calendars, the DAV:principal-property-search
- REPORT can be used to filter on some properties and return others.
- To search for a calendar owned by a user named "Laurie", the REPORT
- request body would look like this:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Laurie
-
-
-
-
-
-
-
- The server performs a case-sensitive or caseless search for a
- matching string subset of "Laurie" within the DAV:displayname
- property. Thus, the server might return "Laurie Dusseault", "Laurier
- Desruisseaux", or "Wilfrid Laurier" as matching DAV:displayname
- values, and return the calendars for each of these.
-
-8.5. Storing and Using Attachments
-
- CalDAV clients MAY create attachments in calendar components either
- as inline or external. This section contains some guidelines for
- creating and managing attachments.
-
-8.5.1. Inline Attachments
-
- CalDAV clients MUST support inline attachments as specified in
- iCalendar [RFC2445]. CalDAV servers MUST support inline attachments,
- so clients can rely on being able to create attachments this way. On
- the other hand, inline attachments have some drawbacks:
-
- o Servers MAY impose limitations on the size of calendar object
- resources (i.e., refusing PUT requests of very large iCalendar
- objects). Servers that impose such limitations MUST use the
- CALDAV:max-resource-size property on a calendar collection to
- inform the client as to what the limitation is (see
- Section 5.2.5).
-
- o Servers MAY impose storage quota limitations on calendar
- collections (See [RFC4331]).
-
- o Any change to a calendar object resource containing an inline
- attachment requires the entire inline attachment to be re-
- uploaded.
-
-
-
-
-
- o Clients synchronizing a changed calendar object resource have to
- download the entire calendar object resource, even if the
- attachment is unchanged.
-
-8.5.2. External Attachments
-
- CalDAV clients SHOULD support downloading of external attachments
- referenced by arbitrary URI schemes, by either processing them
- directly, or by passing the attachment URI to a suitable "helper
- application" for processing, if such an application exists. CalDAV
- clients MUST support downloading of external attachments referenced
- by the "http" or "https" URI schemes. An external attachment could
- be:
-
- o In a collection in the calendar collection containing the calendar
- object resource;
-
- o Somewhere else in the same repository that hosts the calendar
- collection; or
-
- o On an HTTP or FTP server elsewhere.
-
- CalDAV servers MAY provide support for child collections in calendar
- collections. CalDAV servers MAY allow the MKCOL method to create
- child collections in calendar collections. Child collections of
- calendar collections MAY contain any type of resource except calendar
- collections that they MUST NOT contain. Some CalDAV servers won't
- allow child collections in calendar collections, and it may be
- possible on such a server to discover other locations where
- attachments can be stored.
-
- Clients are entirely responsible for maintaining reference
- consistency with calendar components that link to external
- attachments. A client deleting a calendar component with an external
- attachment might therefore also delete the attachment if that's
- appropriate; however, appropriateness can be very hard to determine.
- A new component might easily reference some pre-existing Web resource
- that is intended to have independent existence from the calendar
- component (the "attachment" could be a major proposal to be discussed
- in a meeting, for instance). Best practices will probably emerge and
- should probably be documented, but for now, clients should be wary of
- engaging in aggressive "cleanup" of external attachments. A client
- could involve the user in making decisions about removing
- unreferenced documents, or a client could be conservative in only
- deleting attachments it had created.
-
- Also, clients are responsible for consistency of permissions when
- using external attachments. One reason for servers to support the
-
-
-
-
- storage of attachments within child collections of calendar
- collections is that ACL inheritance might make it easier to grant the
- same permissions to attachments that are granted on the calendar
- collection. Otherwise, it can be very difficult to keep permissions
- synchronized. With attachments stored on separate repositories, it
- can be impossible to keep permissions consistent -- the two
- repositories may not support the same permissions or have the same
- set of principals. Some systems have used tickets or other anonymous
- access control mechanisms to provide partially satisfactory solutions
- to these kinds of problems.
-
-8.6. Storing and Using Alarms
-
- Note that all CalDAV calendar collections (including those the user
- might treat as public or group calendars) can contain alarm
- information on events and to-dos. Users can synchronize a calendar
- between multiple devices and decide to have alarms execute on a
- different device than the device that created the alarm. Not all
- alarm action types are completely interoperable (e.g., those that
- name a sound file to play).
-
- When the action is AUDIO and the client is configured to execute
- the alarm, the client SHOULD play the suggested sound if it's
- available or play another sound, but SHOULD NOT rewrite the alarm
- just to replace the suggested sound with a sound that's locally
- available.
-
- When the action is DISPLAY and the client is configured to execute
- the alarm, the client SHOULD execute a display alarm by displaying
- according to the suggested description or some reasonable
- replacement, but SHOULD NOT rewrite the alarm for its own
- convenience.
-
- When the action is EMAIL and the client is incapable of sending
- email, it SHOULD ignore the alarm, but it MUST continue to
- synchronize the alarm itself.
-
- This specification makes no recommendations about executing alarms
- of type PROCEDURE, except to note that clients are advised to take
- care to avoid creating security holes by executing these.
-
- Non-interoperable alarm information (e.g., should somebody define a
- color to be used in a display alarm) should be put in non-standard
- properties inside the VALARM component in order to keep the basic
- alarm usable on all devices.
-
- Clients that allow changes to calendar object resources MUST
- synchronize the alarm data that already exists in the resources.
-
-
-
-
- Clients MAY execute alarms that are downloaded in this fashion,
- possibly based on user preference. If a client is only doing read
- operations on a calendar and there is no risk of losing alarm
- information, then the client MAY discard alarm information.
-
- This specification makes no attempt to provide multi-user alarms on
- group calendars or to find out for whom an alarm is intended.
- Addressing those issues might require extensions to iCalendar; for
- example, to store alarms per-user, or to indicate for which user a
- VALARM was intended. In the meantime, clients might maximize
- interoperability by generally not uploading alarm information to
- public, group, or resource calendars.
-
-9. XML Element Definitions
-
-9.1. CALDAV:calendar XML Element
-
- Name: calendar
-
- Namespace: urn:ietf:params:xml:ns:caldav
-
- Purpose: Specifies the resource type of a calendar collection.
-
- Description: See Section 4.2.
-
- Definition:
-
-
-
-9.2. CALDAV:mkcalendar XML Element
-
- Name: mkcalendar
-
- Namespace: urn:ietf:params:xml:ns:caldav
-
- Purpose: Specifies a request that includes the WebDAV property
- values to be set for a calendar collection resource when it is
- created.
-
- Description: See Section 5.3.1.
-
- Definition:
-
-
-
-
-
-
-
-
-
-
-9.3. CALDAV:mkcalendar-response XML Element
-
- Name: mkcalendar-response
-
- Namespace: urn:ietf:params:xml:ns:caldav
-
- Purpose: Specifies a response body for a successful MKCALENDAR
- request.
-
- Description: See Section 5.3.1.
-
- Definition:
-
-
-
-9.4. CALDAV:supported-collation XML Element
-
- Name: supported-collation
-
- Namespace: urn:ietf:params:xml:ns:caldav
-
- Purpose: Identifies a single collation via its collation identifier,
- as defined by [RFC4790].
-
- Description: The CALDAV:supported-collation contains the text of a
- collation identifier, as described in Section 7.5.1.
-
- Definition:
-
-
- PCDATA value: collation identifier
-
-9.5. CALDAV:calendar-query XML Element
-
- Name: calendar-query
-
- Namespace: urn:ietf:params:xml:ns:caldav
-
- Purpose: Defines a report for querying calendar object resources.
-
- Description: See Section 7.8.
-
- Definition:
-
-
-
-
-
-
-
-9.6. CALDAV:calendar-data XML Element
-
- Name: calendar-data
-
- Namespace: urn:ietf:params:xml:ns:caldav
-
- Purpose: Specified one of the following:
-
- 1. A supported media type for calendar object resources when
- nested in the CALDAV:supported-calendar-data property;
-
- 2. The parts of a calendar object resource should be returned by
- a calendaring report;
-
- 3. The content of a calendar object resource in a response to a
- calendaring report.
-
- Description: When nested in the CALDAV:supported-calendar-data
- property, the CALDAV:calendar-data XML element specifies a media
- type supported by the CalDAV server for calendar object resources.
-
- When used in a calendaring REPORT request, the CALDAV:calendar-
- data XML element specifies which parts of calendar object
- resources need to be returned in the response. If the CALDAV:
- calendar-data XML element doesn't contain any CALDAV:comp element,
- calendar object resources will be returned in their entirety.
-
- Finally, when used in a calendaring REPORT response, the CALDAV:
- calendar-data XML element specifies the content of a calendar
- object resource. Given that XML parsers normalize the two-
- character sequence CRLF (US-ASCII decimal 13 and US-ASCII decimal
- 10) to a single LF character (US-ASCII decimal 10), the CR
- character (US-ASCII decimal 13) MAY be omitted in calendar object
- resources specified in the CALDAV:calendar-data XML element.
- Furthermore, calendar object resources specified in the CALDAV:
- calendar-data XML element MAY be invalid per their media type
- specification if the CALDAV:calendar-data XML element part of the
- calendaring REPORT request did not specify required properties
- (e.g., UID, DTSTAMP, etc.), or specified a CALDAV:prop XML element
- with the "novalue" attribute set to "yes".
-
- Note: The CALDAV:calendar-data XML element is specified in requests
- and responses inside the DAV:prop XML element as if it were a
- WebDAV property. However, the CALDAV:calendar-data XML element is
- not a WebDAV property and, as such, is not returned in PROPFIND
- responses, nor used in PROPPATCH requests.
-
-
-
-
-
-
- Note: The iCalendar data embedded within the CALDAV:calendar-data
- XML element MUST follow the standard XML character data encoding
- rules, including use of <, >, & etc. entity encoding or
- the use of a construct. In the later case, the
- iCalendar data cannot contain the character sequence "]]>", which
- is the end delimiter for the CDATA section.
-
- Definition:
-
-
-
- when nested in the CALDAV:supported-calendar-data property
- to specify a supported media type for calendar object
- resources;
-
-
-
- when nested in the DAV:prop XML element in a calendaring
- REPORT request to specify which parts of calendar object
- resources should be returned in the response;
-
-
- PCDATA value: iCalendar object
-
- when nested in the DAV:prop XML element in a calendaring
- REPORT response to specify the content of a returned
- calendar object resource.
-
-
- content-type value: a MIME media type
- version value: a version string
-
- attributes can be used on all three variants of the
- CALDAV:calendar-data XML element.
-
-9.6.1. CALDAV:comp XML Element
-
- Name: comp
-
- Namespace: urn:ietf:params:xml:ns:caldav
-
- Purpose: Defines which component types to return.
-
-
-
-
-
-
-
- Description: The name value is a calendar component name (e.g.,
- VEVENT).
-
- Definition:
-
-
-
-
- name value: a calendar component name
-
- Note: The CALDAV:prop and CALDAV:allprop elements have the same name
- as the DAV:prop and DAV:allprop elements defined in [RFC2518].
- However, the CALDAV:prop and CALDAV:allprop elements are defined
- in the "urn:ietf:params:xml:ns:caldav" namespace instead of the
- "DAV:" namespace.
-
-9.6.2. CALDAV:allcomp XML Element
-
- Name: allcomp
-
- Namespace: urn:ietf:params:xml:ns:caldav
-
- Purpose: Specifies that all components shall be returned.
-
- Description: The CALDAV:allcomp XML element can be used when the
- client wants all types of components returned by a calendaring
- REPORT request.
-
- Definition:
-
-
-
-9.6.3. CALDAV:allprop XML Element
-
- Name: allprop
-
- Namespace: urn:ietf:params:xml:ns:caldav
-
- Purpose: Specifies that all properties shall be returned.
-
- Description: The CALDAV:allprop XML element can be used when the
- client wants all properties of components returned by a
- calendaring REPORT request.
-
- Definition:
-
-
-
-
-
-
-
- Note: The CALDAV:allprop element has the same name as the DAV:
- allprop element defined in [RFC2518]. However, the CALDAV:allprop
- element is defined in the "urn:ietf:params:xml:ns:caldav"
- namespace instead of the "DAV:" namespace.
-
-9.6.4. CALDAV:prop XML Element
-
- Name: prop
-
- Namespace: urn:ietf:params:xml:ns:caldav
-
- Purpose: Defines which properties to return in the response.
-
- Description: The "name" attribute specifies the name of the calendar
- property to return (e.g., ATTENDEE). The "novalue" attribute can
- be used by clients to request that the actual value of the
- property not be returned (if the "novalue" attribute is set to
- "yes"). In that case, the server will return just the iCalendar
- property name and any iCalendar parameters and a trailing ":"
- without the subsequent value data.
-
- Definition:
-
-
-
-
- name value: a calendar property name
- novalue value: "yes" or "no"
-
- Note: The CALDAV:prop element has the same name as the DAV:prop
- element defined in [RFC2518]. However, the CALDAV:prop element is
- defined in the "urn:ietf:params:xml:ns:caldav" namespace instead
- of the "DAV:" namespace.
-
-9.6.5. CALDAV:expand XML Element
-
- Name: expand
-
- Namespace: urn:ietf:params:xml:ns:caldav
-
- Purpose: Forces the server to expand recurring components into
- individual recurrence instances.
-
- Description: The CALDAV:expand XML element specifies that for a
- given calendaring REPORT request, the server MUST expand the
- recurrence set into calendar components that define exactly one
-
-
-
-
-
- recurrence instance, and MUST return only those whose scheduled
- time intersect a specified time range.
-
- The "start" attribute specifies the inclusive start of the time
- range, and the "end" attribute specifies the non-inclusive end of
- the time range. Both attributes are specified as date with UTC
- time value. The value of the "end" attribute MUST be greater than
- the value of the "start" attribute.
-
- The server MUST use the same logic as defined for CALDAV:time-
- range to determine if a recurrence instance intersects the
- specified time range.
-
- Recurring components, other than the initial instance, MUST
- include a RECURRENCE-ID property indicating which instance they
- refer to.
-
- The returned calendar components MUST NOT use recurrence
- properties (i.e., EXDATE, EXRULE, RDATE, and RRULE) and MUST NOT
- have reference to or include VTIMEZONE components. Date and local
- time with reference to time zone information MUST be converted
- into date with UTC time.
-
- Definition:
-
-
-
-
- start value: an iCalendar "date with UTC time"
- end value: an iCalendar "date with UTC time"
-
-9.6.6. CALDAV:limit-recurrence-set XML Element
-
- Name: limit-recurrence-set
-
- Namespace: urn:ietf:params:xml:ns:caldav
-
- Purpose: Specifies a time range to limit the set of "overridden
- components" returned by the server.
-
- Description: The CALDAV:limit-recurrence-set XML element specifies
- that for a given calendaring REPORT request, the server MUST
- return, in addition to the "master component", only the
- "overridden components" that impact a specified time range. An
- overridden component impacts a time range if its current start and
- end times overlap the time range, or if the original start and end
-
-
-
-
-
- times -- the ones that would have been used if the instance were
- not overridden -- overlap the time range.
-
- The "start" attribute specifies the inclusive start of the time
- range, and the "end" attribute specifies the non-inclusive end of
- the time range. Both attributes are specified as date with UTC
- time value. The value of the "end" attribute MUST be greater than
- the value of the "start" attribute.
-
- The server MUST use the same logic as defined for CALDAV:time-
- range to determine if the current or original scheduled time of an
- "overridden" recurrence instance intersects the specified time
- range.
-
- Overridden components that have a RANGE parameter on their
- RECURRENCE-ID property may specify one or more instances in the
- recurrence set, and some of those instances may fall within the
- specified time range or may have originally fallen within the
- specified time range prior to being overridden. If that is the
- case, the overridden component MUST be included in the results, as
- it has a direct impact on the interpretation of instances within
- the specified time range.
-
- Definition:
-
-
-
-
- start value: an iCalendar "date with UTC time"
- end value: an iCalendar "date with UTC time"
-
-9.6.7. CALDAV:limit-freebusy-set XML Element
-
- Name: limit-freebusy-set
-
- Namespace: urn:ietf:params:xml:ns:caldav
-
- Purpose: Specifies a time range to limit the set of FREEBUSY values
- returned by the server.
-
- Description: The CALDAV:limit-freebusy-set XML element specifies
- that for a given calendaring REPORT request, the server MUST only
- return the FREEBUSY property values of a VFREEBUSY component that
- intersects a specified time range.
-
- The "start" attribute specifies the inclusive start of the time
- range, and the "end" attribute specifies the non-inclusive end of
-
-
-
-
- the time range. Both attributes are specified as "date with UTC
- time" value. The value of the "end" attribute MUST be greater
- than the value of the "start" attribute.
-
- The server MUST use the same logic as defined for CALDAV:time-
- range to determine if a FREEBUSY property value intersects the
- specified time range.
-
- Definition:
-
-
-
-
- start value: an iCalendar "date with UTC time"
- end value: an iCalendar "date with UTC time"
-
-9.7. CALDAV:filter XML Element
-
- Name: filter
-
- Namespace: urn:ietf:params:xml:ns:caldav
-
- Purpose: Specifies a filter to limit the set of calendar components
- returned by the server.
-
- Description: The CALDAV:filter XML element specifies the search
- filter used to limit the calendar components returned by a
- calendaring REPORT request.
-
- Definition:
-
-
-
-9.7.1. CALDAV:comp-filter XML Element
-
- Name: comp-filter
-
- Namespace: urn:ietf:params:xml:ns:caldav
-
- Purpose: Specifies search criteria on calendar components.
-
- Description: The CALDAV:comp-filter XML element specifies a query
- targeted at the calendar object (i.e., VCALENDAR) or at a specific
- calendar component type (e.g., VEVENT). The scope of the
- CALDAV:comp-filter XML element is the calendar object when used as
- a child of the CALDAV:filter XML element. The scope of the
- CALDAV:comp-filter XML element is the enclosing calendar component
-
-
-
-
- when used as a child of another CALDAV:comp-filter XML element. A
- CALDAV:comp-filter is said to match if:
-
- * The CALDAV:comp-filter XML element is empty and the calendar
- object or calendar component type specified by the "name"
- attribute exists in the current scope;
-
- or:
-
- * The CALDAV:comp-filter XML element contains a CALDAV:is-not-
- defined XML element and the calendar object or calendar
- component type specified by the "name" attribute does not exist
- in the current scope;
-
- or:
-
- * The CALDAV:comp-filter XML element contains a CALDAV:time-range
- XML element and at least one recurrence instance in the
- targeted calendar component is scheduled to overlap the
- specified time range, and all specified CALDAV:prop-filter and
- CALDAV:comp-filter child XML elements also match the targeted
- calendar component;
-
- or:
-
- * The CALDAV:comp-filter XML element only contains CALDAV:prop-
- filter and CALDAV:comp-filter child XML elements that all match
- the targeted calendar component.
-
- Definition:
-
-
-
-
- name value: a calendar object or calendar component
- type (e.g., VEVENT)
-
-9.7.2. CALDAV:prop-filter XML Element
-
- Name: prop-filter
-
- Namespace: urn:ietf:params:xml:ns:caldav
-
- Purpose: Specifies search criteria on calendar properties.
-
- Description: The CALDAV:prop-filter XML element specifies a query
- targeted at a specific calendar property (e.g., CATEGORIES) in the
-
-
-
-
- scope of the enclosing calendar component. A calendar property is
- said to match a CALDAV:prop-filter if:
-
- * The CALDAV:prop-filter XML element is empty and a property of
- the type specified by the "name" attribute exists in the
- enclosing calendar component;
-
- or:
-
- * The CALDAV:prop-filter XML element contains a CALDAV:is-not-
- defined XML element and no property of the type specified by
- the "name" attribute exists in the enclosing calendar
- component;
-
- or:
-
- * The CALDAV:prop-filter XML element contains a CALDAV:time-range
- XML element and the property value overlaps the specified time
- range, and all specified CALDAV:param-filter child XML elements
- also match the targeted property;
-
- or:
-
- * The CALDAV:prop-filter XML element contains a CALDAV:text-match
- XML element and the property value matches it, and all
- specified CALDAV:param-filter child XML elements also match the
- targeted property;
-
- Definition:
-
-
-
-
- name value: a calendar property name (e.g., ATTENDEE)
-
-9.7.3. CALDAV:param-filter XML Element
-
- Name: param-filter
-
- Namespace: urn:ietf:params:xml:ns:caldav
-
- Purpose: Limits the search to specific parameter values.
-
- Description: The CALDAV:param-filter XML element specifies a query
- targeted at a specific calendar property parameter (e.g.,
- PARTSTAT) in the scope of the calendar property on which it is
-
-
-
-
- defined. A calendar property parameter is said to match a CALDAV:
- param-filter if:
-
- * The CALDAV:param-filter XML element is empty and a parameter of
- the type specified by the "name" attribute exists on the
- calendar property being examined;
-
- or:
-
- * The CALDAV:param-filter XML element contains a CALDAV:is-not-
- defined XML element and no parameter of the type specified by
- the "name" attribute exists on the calendar property being
- examined;
-
- Definition:
-
-
-
-
- name value: a property parameter name (e.g., PARTSTAT)
-
-9.7.4. CALDAV:is-not-defined XML Element
-
- Name: is-not-defined
-
- Namespace: urn:ietf:params:xml:ns:caldav
-
- Purpose: Specifies that a match should occur if the enclosing
- component, property, or parameter does not exist.
-
- Description: The CALDAV:is-not-defined XML element specifies that a
- match occurs if the enclosing component, property, or parameter
- value specified in a calendaring REPORT request does not exist in
- the calendar data being tested.
-
- Definition:
-
-
-
-9.7.5. CALDAV:text-match XML Element
-
- Name: text-match
-
- Namespace: urn:ietf:params:xml:ns:caldav
-
- Purpose: Specifies a substring match on a property or parameter
- value.
-
-
-
-
-
- Description: The CALDAV:text-match XML element specifies text used
- for a substring match against the property or parameter value
- specified in a calendaring REPORT request.
-
- The "collation" attribute is used to select the collation that the
- server MUST use for character string matching. In the absence of
- this attribute, the server MUST use the "i;ascii-casemap"
- collation.
-
- The "negate-condition" attribute is used to indicate that this
- test returns a match if the text matches when the attribute value
- is set to "no", or return a match if the text does not match, if
- the attribute value is set to "yes". For example, this can be
- used to match components with a STATUS property not set to
- CANCELLED.
-
- Definition:
-
-
- PCDATA value: string
-
-
-
-9.8. CALDAV:timezone XML Element
-
- Name: timezone
-
- Namespace: urn:ietf:params:xml:ns:caldav
-
- Purpose: Specifies the time zone component to use when determining
- the results of a report.
-
- Description: The CALDAV:timezone XML element specifies that for a
- given calendaring REPORT request, the server MUST rely on the
- specified VTIMEZONE component instead of the CALDAV:calendar-
- timezone property of the calendar collection, in which the
- calendar object resource is contained to resolve "date" values and
- "date with local time" values (i.e., floating time) to "date with
- UTC time" values. The server will require this information to
- determine if a calendar component scheduled with "date" values or
- "date with local time" values intersects a CALDAV:time-range
- specified in a CALDAV:calendar-query REPORT.
-
- Note: The iCalendar data embedded within the CALDAV:timezone XML
- element MUST follow the standard XML character data encoding
- rules, including use of <, >, & etc. entity encoding or
- the use of a construct. In the later case, the
-
-
-
-
- iCalendar data cannot contain the character sequence "]]>", which
- is the end delimiter for the CDATA section.
-
- Definition:
-
-
- PCDATA value: an iCalendar object with exactly one VTIMEZONE
-
-9.9. CALDAV:time-range XML Element
-
- Name: time-range
-
- Namespace: urn:ietf:params:xml:ns:caldav
-
- Purpose: Specifies a time range to limit the set of calendar
- components returned by the server.
-
- Description: The CALDAV:time-range XML element specifies that for a
- given calendaring REPORT request, the server MUST only return the
- calendar object resources that, depending on the context, have a
- component or property whose value intersects a specified time
- range.
-
- The "start" attribute specifies the inclusive start of the time
- range, and the "end" attribute specifies the non-inclusive end of
- the time range. Both attributes MUST be specified as "date with
- UTC time" value. Time ranges open at one end can be specified by
- including only one attribute; however, at least one attribute MUST
- always be present in the CALDAV:time-range element. If either the
- "start" or "end" attribute is not specified in the CALDAV:time-
- range XML element, assume "-infinity" and "+infinity" as their
- value, respectively. If both "start" and "end" are present, the
- value of the "end" attribute MUST be greater than the value of the
- "start" attribute.
-
- Time range tests MUST consider every recurrence instance when
- testing the time range condition; if any one instance matches,
- then the test returns true. Testing recurrence instances requires
- the server to infer an effective value for DTSTART, DTEND,
- DURATION, and DUE properties for an instance based on the
- recurrence patterns and any overrides.
-
- A VEVENT component overlaps a given time range if the condition
- for the corresponding component state specified in the table below
- is satisfied. Note that, as specified in [RFC2445], the DTSTART
- property is REQUIRED in the VEVENT component. The conditions
- depend on the presence of the DTEND and DURATION properties in the
- VEVENT component. Furthermore, the value of the DTEND property
-
-
-
-
- MUST be later in time than the value of the DTSTART property. The
- duration of a VEVENT component with no DTEND and DURATION
- properties is 1 day (+P1D) when the DTSTART is a DATE value, and 0
- seconds when the DTSTART is a DATE-TIME value.
-
- +---------------------------------------------------------------+
- | VEVENT has the DTEND property? |
- | +-----------------------------------------------------------+
- | | VEVENT has the DURATION property? |
- | | +-------------------------------------------------------+
- | | | DURATION property value is greater than 0 seconds? |
- | | | +---------------------------------------------------+
- | | | | DTSTART property is a DATE-TIME value? |
- | | | | +-----------------------------------------------+
- | | | | | Condition to evaluate |
- +---+---+---+---+-----------------------------------------------+
- | Y | N | N | * | (start < DTEND AND end > DTSTART) |
- +---+---+---+---+-----------------------------------------------+
- | N | Y | Y | * | (start < DTSTART+DURATION AND end > DTSTART) |
- | | +---+---+-----------------------------------------------+
- | | | N | * | (start <= DTSTART AND end > DTSTART) |
- +---+---+---+---+-----------------------------------------------+
- | N | N | N | Y | (start <= DTSTART AND end > DTSTART) |
- +---+---+---+---+-----------------------------------------------+
- | N | N | N | N | (start < DTSTART+P1D AND end > DTSTART) |
- +---+---+---+---+-----------------------------------------------+
-
- A VTODO component is said to overlap a given time range if the
- condition for the corresponding component state specified in the
- table below is satisfied. The conditions depend on the presence
- of the DTSTART, DURATION, DUE, COMPLETED, and CREATED properties
- in the VTODO component. Note that, as specified in [RFC2445], the
- DUE value MUST be a DATE-TIME value equal to or after the DTSTART
- value if specified.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- +-------------------------------------------------------------------+
- | VTODO has the DTSTART property? |
- | +---------------------------------------------------------------+
- | | VTODO has the DURATION property? |
- | | +-----------------------------------------------------------+
- | | | VTODO has the DUE property? |
- | | | +-------------------------------------------------------+
- | | | | VTODO has the COMPLETED property? |
- | | | | +---------------------------------------------------+
- | | | | | VTODO has the CREATED property? |
- | | | | | +-----------------------------------------------+
- | | | | | | Condition to evaluate |
- +---+---+---+---+---+-----------------------------------------------+
- | Y | Y | N | * | * | (start <= DTSTART+DURATION) AND |
- | | | | | | ((end > DTSTART) OR |
- | | | | | | (end >= DTSTART+DURATION)) |
- +---+---+---+---+---+-----------------------------------------------+
- | Y | N | Y | * | * | ((start < DUE) OR (start <= DTSTART)) |
- | | | | | | AND |
- | | | | | | ((end > DTSTART) OR (end >= DUE)) |
- +---+---+---+---+---+-----------------------------------------------+
- | Y | N | N | * | * | (start <= DTSTART) AND (end > DTSTART) |
- +---+---+---+---+---+-----------------------------------------------+
- | N | N | Y | * | * | (start < DUE) AND (end >= DUE) |
- +---+---+---+---+---+-----------------------------------------------+
- | N | N | N | Y | Y | ((start <= CREATED) OR (start <= COMPLETED))|
- | | | | | | AND |
- | | | | | | ((end >= CREATED) OR (end >= COMPLETED))|
- +---+---+---+---+---+-----------------------------------------------+
- | N | N | N | Y | N | (start <= COMPLETED) AND (end >= COMPLETED) |
- +---+---+---+---+---+-----------------------------------------------+
- | N | N | N | N | Y | (end > CREATED) |
- +---+---+---+---+---+-----------------------------------------------+
- | N | N | N | N | N | TRUE |
- +---+---+---+---+---+-----------------------------------------------+
-
- A VJOURNAL component overlaps a given time range if the condition
- for the corresponding component state specified in the table below
- is satisfied. The conditions depend on the presence of the
- DTSTART property in the VJOURNAL component and on whether the
- DTSTART is a DATE-TIME or DATE value. The effective "duration" of
- a VJOURNAL component is 1 day (+P1D) when the DTSTART is a DATE
- value, and 0 seconds when the DTSTART is a DATE-TIME value.
-
-
-
-
-
-
-
-
-
- +----------------------------------------------------+
- | VJOURNAL has the DTSTART property? |
- | +------------------------------------------------+
- | | DTSTART property is a DATE-TIME value? |
- | | +--------------------------------------------+
- | | | Condition to evaluate |
- +---+---+--------------------------------------------+
- | Y | Y | (start <= DTSTART) AND (end > DTSTART) |
- +---+---+--------------------------------------------+
- | Y | N | (start < DTSTART+P1D) AND (end > DTSTART) |
- +---+---+--------------------------------------------+
- | N | * | FALSE |
- +---+---+--------------------------------------------+
-
- A VFREEBUSY component overlaps a given time range if the condition
- for the corresponding component state specified in the table below
- is satisfied. The conditions depend on the presence in the
- VFREEBUSY component of the DTSTART and DTEND properties, and any
- FREEBUSY properties in the absence of DTSTART and DTEND. Any
- DURATION property is ignored, as it has a special meaning when
- used in a VFREEBUSY component.
-
- When only FREEBUSY properties are used, each period in each
- FREEBUSY property is compared against the time range, irrespective
- of the type of free busy information (free, busy, busy-tentative,
- busy-unavailable) represented by the property.
-
-
- +------------------------------------------------------+
- | VFREEBUSY has both the DTSTART and DTEND properties? |
- | +--------------------------------------------------+
- | | VFREEBUSY has the FREEBUSY property? |
- | | +----------------------------------------------+
- | | | Condition to evaluate |
- +---+---+----------------------------------------------+
- | Y | * | (start <= DTEND) AND (end > DTSTART) |
- +---+---+----------------------------------------------+
- | N | Y | (start < freebusy-period-end) AND |
- | | | (end > freebusy-period-start) |
- +---+---+----------------------------------------------+
- | N | N | FALSE |
- +---+---+----------------------------------------------+
-
- A VALARM component is said to overlap a given time range if the
- following condition holds:
-
- (start <= trigger-time) AND (end > trigger-time)
-
-
-
-
-
- A VALARM component can be defined such that it triggers repeatedly.
- Such a VALARM component is said to overlap a given time range if at
- least one of its triggers overlaps the time range.
-
- The calendar properties COMPLETED, CREATED, DTEND, DTSTAMP,
- DTSTART, DUE, and LAST-MODIFIED overlap a given time range if the
- following condition holds:
-
- (start <= date-time) AND (end > date-time)
-
- Note that if DTEND is not present in a VEVENT, but DURATION is, then
- the test should instead operate on the 'effective' DTEND, i.e.,
- DTSTART+DURATION. Similarly, if DUE is not present in a VTODO, but
- DTSTART and DURATION are, then the test should instead operate on the
- 'effective' DUE, i.e., DTSTART+DURATION.
-
- The semantic of CALDAV:time-range is not defined for any other
- calendar components and properties.
-
- Definition:
-
-
-
-
- start value: an iCalendar "date with UTC time"
- end value: an iCalendar "date with UTC time"
-
-9.10. CALDAV:calendar-multiget XML Element
-
- Name: calendar-multiget
-
- Namespace: urn:ietf:params:xml:ns:caldav
-
- Purpose: CalDAV report used to retrieve specific calendar object
- resources.
-
- Description: See Section 7.9.
-
- Definition:
-
-
-
-
-
-
-
-
-
-
-9.11. CALDAV:free-busy-query XML Element
-
- Name: free-busy-query
-
- Namespace: urn:ietf:params:xml:ns:caldav
-
- Purpose: CalDAV report used to generate a VFREEBUSY to determine
- busy time over a specific time range.
-
- Description: See Section 7.10.
-
- Definition:
-
-
-
-10. Internationalization Considerations
-
- CalDAV allows internationalized strings to be stored and retrieved
- for the description of calendar collections (see Section 5.2.1).
-
- The CALDAV:calendar-query REPORT (Section 7.8) includes a text
- searching option controlled by the CALDAV:text-match element, and
- details of character handling are covered in the description of that
- element (see Section 9.7.5).
-
-11. Security Considerations
-
- HTTP protocol transactions are sent in the clear over the network
- unless protection from snooping is negotiated. This can be
- accomplished by use of TLS, as defined in [RFC2818]. In particular,
- HTTP Basic authentication MUST NOT be used unless TLS is in effect.
-
- Servers MUST take adequate precautions to ensure that malicious
- clients cannot consume excessive server resources (CPU, memory, disk,
- etc.) through carefully crafted reports. For example, a client could
- upload an event with a recurrence rule that specifies a recurring
- event occurring every second for the next 100 years, which would
- result in approximately 3 x 10^9 instances! A report that asks for
- recurrences to be expanded over that range would likely constitute a
- denial-of-service attack on the server.
-
- When creating new resources (including calendar collections), clients
- MUST ensure that the resource name (the last path segment of the
- resource URI) assigned to the new resource does not expose any data
- from within the iCalendar resource itself or information about the
- nature of a calendar collection. This is required to ensure that the
- presence of a specific iCalendar component or nature of components in
- a collection cannot be inferred based on the name of a resource.
-
-
-
-
- When rolling up free-busy information, more information about a
- user's events is exposed if busy periods overlap or are adjacent
- (this tells the client requesting the free-busy information that the
- calendar owner has at least two events, rather than knowing only that
- the calendar owner has one or more events during the busy period).
- Thus, a conservative approach to calendar data privacy would have
- servers always coalesce such busy periods when they are the same
- type.
-
- Procedure alarms are a known security risk for either clients or
- servers to handle, particularly when the alarm was created by another
- agent. Clients and servers are not required to execute such
- procedure alarms.
-
- Security considerations described in iCalendar [RFC2445] and iTIP
- [RFC2446] are also applicable to CalDAV.
-
- Beyond these, CalDAV does not raise any security considerations that
- are not present in HTTP [RFC2616] and WebDAV [RFC2518], [RFC3253],
- [RFC3744].
-
-12. IANA Considerations
-
- This document uses one new URN to identify a new XML namespace. The
- URN conforms to a registry mechanism described in [RFC3688].
-
-12.1. Namespace Registration
-
- Registration request for the CalDAV namespace:
-
- URI: urn:ietf:params:xml:ns:caldav
-
- Registrant Contact: See the "Authors' Addresses" section of this
- document.
-
- XML: None. Namespace URIs do not represent an XML specification.
-
-13. Acknowledgements
-
- The authors would like to thank the following individuals for
- contributing their ideas and support for writing this specification:
- Michael Arick, Mario Bonin, Chris Bryant, Scott Carr, Andre
- Courtemanche, Mike Douglass, Ted Hardie, Marten den Haring, Jeffrey
- Harris, Sam Hartman, Helge Hess, Jeff McCullough, Alexey Melnikov,
- Dan Mosedale, Brian Moseley, Francois Perrault, Kervin L. Pierre,
- Julian F. Reschke, Wilfredo Sanchez Vega, Mike Shaver, Jari
- Urpalainen, Simon Vaillancourt, and Jim Whitehead.
-
-
-
-
-
- The authors would also like to thank the Calendaring and Scheduling
- Consortium for advice with this specification, and for organizing
- interoperability testing events to help refine it.
-
-14. References
-
-14.1. Normative References
-
- [RFC2119] Bradner, S., "Key words for use in RFCs to
- Indicate Requirement Levels", BCP 14,
- RFC 2119, March 1997.
-
- [RFC2246] Dierks, T. and C. Allen, "The TLS Protocol
- Version 1.0", RFC 2246, January 1999.
-
- [RFC2445] Dawson, F. and Stenerson, D., "Internet
- Calendaring and Scheduling Core Object
- Specification (iCalendar)", RFC 2445,
- November 1998.
-
- [RFC2446] Silverberg, S., Mansour, S., Dawson, F., and
- R. Hopson, "iCalendar Transport-Independent
- Interoperability Protocol (iTIP) Scheduling
- Events, BusyTime, To-dos and Journal
- Entries", RFC 2446, November 1998.
-
- [RFC2518] Goland, Y., Whitehead, E., Faizi, A., Carter,
- S., and D. Jensen, "HTTP Extensions for
- Distributed Authoring -- WEBDAV", RFC 2518,
- February 1999.
-
- [RFC2616] Fielding, R., Gettys, J., Mogul, J., Frystyk,
- H., Masinter, L., Leach, P., and T. Berners-
- Lee, "Hypertext Transfer Protocol --
- HTTP/1.1", RFC 2616, June 1999.
-
- [RFC2818] Rescorla, E., "HTTP Over TLS", RFC 2818,
- May 2000.
-
- [RFC3253] Clemm, G., Amsden, J., Ellison, T., Kaler,
- C., and J. Whitehead, "Versioning Extensions
- to WebDAV (Web Distributed Authoring and
- Versioning)", RFC 3253, March 2002.
-
- [RFC3688] Mealling, M., "The IETF XML Registry",
- BCP 81, RFC 3688, January 2004.
-
-
-
-
-
-
- [RFC3744] Clemm, G., Reschke, J., Sedlar, E., and J.
- Whitehead, "Web Distributed Authoring and
- Versioning (WebDAV) Access Control Protocol",
- RFC 3744, May 2004.
-
- [RFC4346] Dierks, T. and E. Rescorla, "The Transport
- Layer Security (TLS) Protocol Version 1.1",
- RFC 4346, April 2006.
-
- [RFC4790] Newman, C., Duerst, M., and A. Gulbrandsen,
- "Internet Application Protocol Collation
- Registry", RFC 4790, March 2007.
-
- [W3C.REC-xml-20060816] Paoli, J., Maler, E., Yergeau, F., Sperberg-
- McQueen, C., and T. Bray, "Extensible Markup
- Language (XML) 1.0 (Fourth Edition)", World
- Wide Web Consortium Recommendation REC-xml-
- 20060816, August 2006,
- .
-
-14.2. Informative References
-
- [RFC2426] Dawson, F. and T. Howes, "vCard MIME
- Directory Profile", RFC 2426, September 1998.
-
- [RFC2739] Small, T., Hennessy, D., and F. Dawson,
- "Calendar Attributes for vCard and LDAP",
- RFC 2739, January 2000.
-
- [RFC4331] Korver, B. and L. Dusseault, "Quota and Size
- Properties for Distributed Authoring and
- Versioning (DAV) Collections", RFC 4331,
- February 2006.
-
- [RFC4511] Sermersheim, J., "Lightweight Directory
- Access Protocol (LDAP): The Protocol",
- RFC 4511, June 2006.
-
- [rfc2518bis] Dusseault, L., "HTTP Extensions for
- Distributed Authoring - WebDAV", Work
- in Progress, December 2006.
-
-
-
-
-
-
-
-
-
-
-
-Appendix A. CalDAV Method Privilege Table (Normative)
-
- The following table extends the WebDAV Method Privilege Table
- specified in Appendix B of [RFC3744].
-
- +------------+------------------------------------------------------+
- | METHOD | PRIVILEGES |
- +------------+------------------------------------------------------+
- | MKCALENDAR | DAV:bind |
- | REPORT | DAV:read or CALDAV:read-free-busy (on all referenced |
- | | resources) |
- +------------+------------------------------------------------------+
-
-Appendix B. Calendar Collections Used in the Examples
-
- This appendix shows the calendar object resources contained in the
- calendar collection queried in the examples throughout this document.
-
- The content of the calendar collection is being shown as if it were
- returned by a CALDAV:calendar-query REPORT request designed to return
- all the calendar data in the collection:
-
- >> Request <<
-
- REPORT /bernard/work/ HTTP/1.1
- Host: cal.example.com
- Depth: 1
- Content-Type: application/xml; charset="utf-8"
- Content-Length: xxxx
-
-
-
-
-
-
-
-
-
-
-
-
- >> Response <<
-
- HTTP/1.1 207 Multi-Status
- Content-Type: application/xml; charset="utf-8"
- Content-Length: xxxx
-
-
-
-
-
-
-
-
-
- http://cal.example.com/bernard/work/abcd1.ics
-
-
- "fffff-abcd1"
- BEGIN:VCALENDAR
- VERSION:2.0
- PRODID:-//Example Corp.//CalDAV Client//EN
- BEGIN:VTIMEZONE
- LAST-MODIFIED:20040110T032845Z
- TZID:US/Eastern
- BEGIN:DAYLIGHT
- DTSTART:20000404T020000
- RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
- TZNAME:EDT
- TZOFFSETFROM:-0500
- TZOFFSETTO:-0400
- END:DAYLIGHT
- BEGIN:STANDARD
- DTSTART:20001026T020000
- RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
- TZNAME:EST
- TZOFFSETFROM:-0400
- TZOFFSETTO:-0500
- END:STANDARD
- END:VTIMEZONE
- BEGIN:VEVENT
- DTSTAMP:20060206T001102Z
- DTSTART;TZID=US/Eastern:20060102T100000
- DURATION:PT1H
- SUMMARY:Event #1
- Description:Go Steelers!
- UID:74855313FA803DA593CD579A@example.com
- END:VEVENT
- END:VCALENDAR
-
-
- HTTP/1.1 200 OK
-
-
-
-
- http://cal.example.com/bernard/work/abcd2.ics
-
-
-
-
-
-
- "fffff-abcd2"
- BEGIN:VCALENDAR
- VERSION:2.0
- PRODID:-//Example Corp.//CalDAV Client//EN
- BEGIN:VTIMEZONE
- LAST-MODIFIED:20040110T032845Z
- TZID:US/Eastern
- BEGIN:DAYLIGHT
- DTSTART:20000404T020000
- RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
- TZNAME:EDT
- TZOFFSETFROM:-0500
- TZOFFSETTO:-0400
- END:DAYLIGHT
- BEGIN:STANDARD
- DTSTART:20001026T020000
- RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
- TZNAME:EST
- TZOFFSETFROM:-0400
- TZOFFSETTO:-0500
- END:STANDARD
- END:VTIMEZONE
- BEGIN:VEVENT
- DTSTAMP:20060206T001121Z
- DTSTART;TZID=US/Eastern:20060102T120000
- DURATION:PT1H
- RRULE:FREQ=DAILY;COUNT=5
- SUMMARY:Event #2
- UID:00959BC664CA650E933C892C@example.com
- END:VEVENT
- BEGIN:VEVENT
- DTSTAMP:20060206T001121Z
- DTSTART;TZID=US/Eastern:20060104T140000
- DURATION:PT1H
- RECURRENCE-ID;TZID=US/Eastern:20060104T120000
- SUMMARY:Event #2 bis
- UID:00959BC664CA650E933C892C@example.com
- END:VEVENT
- END:VCALENDAR
-
-
- HTTP/1.1 200 OK
-
-
-
-
- http://cal.example.com/bernard/work/abcd3.ics
-
-
-
-
-
-
- "fffff-abcd3"
- BEGIN:VCALENDAR
- VERSION:2.0
- PRODID:-//Example Corp.//CalDAV Client//EN
- BEGIN:VTIMEZONE
- LAST-MODIFIED:20040110T032845Z
- TZID:US/Eastern
- BEGIN:DAYLIGHT
- DTSTART:20000404T020000
- RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
- TZNAME:EDT
- TZOFFSETFROM:-0500
- TZOFFSETTO:-0400
- END:DAYLIGHT
- BEGIN:STANDARD
- DTSTART:20001026T020000
- RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
- TZNAME:EST
- TZOFFSETFROM:-0400
- TZOFFSETTO:-0500
- END:STANDARD
- END:VTIMEZONE
- BEGIN:VEVENT
- ATTENDEE;PARTSTAT=ACCEPTED;ROLE=CHAIR:mailto:cyrus@example.com
- ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:lisa@example.com
- DTSTAMP:20060206T001220Z
- DTSTART;TZID=US/Eastern:20060104T100000
- DURATION:PT1H
- LAST-MODIFIED:20060206T001330Z
- ORGANIZER:mailto:cyrus@example.com
- SEQUENCE:1
- STATUS:TENTATIVE
- SUMMARY:Event #3
- UID:DC6C50A017428C5216A2F1CD@example.com
- END:VEVENT
- END:VCALENDAR
-
-
- HTTP/1.1 200 OK
-
-
-
-
- http://cal.example.com/bernard/work/abcd4.ics
-
-
-
-
-
-
- "fffff-abcd4"
- BEGIN:VCALENDAR
- VERSION:2.0
- PRODID:-//Example Corp.//CalDAV Client//EN
- BEGIN:VTODO
- DTSTAMP:20060205T235335Z
- DUE;VALUE=DATE:20060104
- STATUS:NEEDS-ACTION
- SUMMARY:Task #1
- UID:DDDEEB7915FA61233B861457@example.com
- BEGIN:VALARM
- ACTION:AUDIO
- TRIGGER;RELATED=START:-PT10M
- END:VALARM
- END:VTODO
- END:VCALENDAR
-
-
- HTTP/1.1 200 OK
-
-
-
-
- http://cal.example.com/bernard/work/abcd5.ics
-
-
- "fffff-abcd5"
- BEGIN:VCALENDAR
- VERSION:2.0
- PRODID:-//Example Corp.//CalDAV Client//EN
- BEGIN:VTODO
- DTSTAMP:20060205T235300Z
- DUE;VALUE=DATE:20060106
- LAST-MODIFIED:20060205T235308Z
- SEQUENCE:1
- STATUS:NEEDS-ACTION
- SUMMARY:Task #2
- UID:E10BA47467C5C69BB74E8720@example.com
- BEGIN:VALARM
- ACTION:AUDIO
- TRIGGER;RELATED=START:-PT10M
- END:VALARM
- END:VTODO
- END:VCALENDAR
-
-
- HTTP/1.1 200 OK
-
-
-
-
-
-
-
-
- http://cal.example.com/bernard/work/abcd6.ics
-
-
- "fffff-abcd6"
- BEGIN:VCALENDAR
- VERSION:2.0
- PRODID:-//Example Corp.//CalDAV Client//EN
- BEGIN:VTODO
- COMPLETED:20051223T122322Z
- DTSTAMP:20060205T235400Z
- DUE;VALUE=DATE:20051225
- LAST-MODIFIED:20060205T235308Z
- SEQUENCE:1
- STATUS:COMPLETED
- SUMMARY:Task #3
- UID:E10BA47467C5C69BB74E8722@example.com
- END:VTODO
- END:VCALENDAR
-
-
- HTTP/1.1 200 OK
-
-
-
-
- http://cal.example.com/bernard/work/abcd7.ics
-
-
- "fffff-abcd7"
- BEGIN:VCALENDAR
- VERSION:2.0
- PRODID:-//Example Corp.//CalDAV Client//EN
- BEGIN:VTODO
- DTSTAMP:20060205T235600Z
- DUE;VALUE=DATE:20060101
- LAST-MODIFIED:20060205T235308Z
- SEQUENCE:1
- STATUS:CANCELLED
- SUMMARY:Task #4
- UID:E10BA47467C5C69BB74E8725@example.com
- END:VTODO
- END:VCALENDAR
-
-
- HTTP/1.1 200 OK
-
-
-
-
-
-
-
-
- http://cal.example.com/bernard/work/abcd8.ics
-
-
- "fffff-abcd8"
- BEGIN:VCALENDAR
- VERSION:2.0
- PRODID:-//Example Corp.//CalDAV Client//EN
- BEGIN:VFREEBUSY
- ORGANIZER;CN="Bernard Desruisseaux":mailto:bernard@example.com
- UID:76ef34-54a3d2@example.com
- DTSTAMP:20050530T123421Z
- DTSTART:20060101T000000Z
- DTEND:20060108T000000Z
- FREEBUSY:20050531T230000Z/20050601T010000Z
- FREEBUSY;FBTYPE=BUSY-TENTATIVE:20060102T100000Z/20060102T120000Z
- FREEBUSY:20060103T100000Z/20060103T120000Z
- FREEBUSY:20060104T100000Z/20060104T120000Z
- FREEBUSY;FBTYPE=BUSY-UNAVAILABLE:20060105T100000Z/20060105T120000Z
- FREEBUSY:20060106T100000Z/20060106T120000Z
- END:VFREEBUSY
- END:VCALENDAR
-
-
- HTTP/1.1 200 OK
-
-
-
-
diff --git a/lib/servers/calendar/caldav/xml.v b/lib/servers/calendar/caldav/xml.v
deleted file mode 100644
index f9bc99f8..00000000
--- a/lib/servers/calendar/caldav/xml.v
+++ /dev/null
@@ -1,166 +0,0 @@
-module caldav
-
-import calendar.calbox
-import encoding.xml
-
-// XML namespace for CalDAV
-const caldav_ns = 'urn:ietf:params:xml:ns:caldav'
-
-// Parses a MKCALENDAR request body
-pub fn parse_mkcalendar(body string) !map[string]string {
- doc := xml.parse(body) or { return error('Invalid XML') }
-
- mut props := map[string]string{}
-
- // Find set element
- set := doc.get_element('set') or { return error('Missing set element') }
-
- // Find prop element
- prop := set.get_element('prop') or { return error('Missing prop element') }
-
- // Parse properties
- for child in prop.children {
- match child.name {
- 'displayname' {
- props['displayname'] = child.text()
- }
- 'calendar-description' {
- props['calendar-description'] = child.text()
- }
- 'calendar-timezone' {
- props['calendar-timezone'] = child.text()
- }
- 'supported-calendar-component-set' {
- mut components := []string{}
- for comp in child.children {
- if comp.name == 'comp' {
- if name := comp.attributes['name'] {
- components << name
- }
- }
- }
- props['supported-calendar-component-set'] = components.join(',')
- }
- else {}
- }
- }
-
- return props
-}
-
-// Parses a calendar-query REPORT request body
-pub fn parse_calendar_query(body string) !CalendarQueryFilter {
- doc := xml.parse(body) or { return error('Invalid XML') }
-
- mut filter := CalendarQueryFilter{}
-
- // Find filter element
- filter_elem := doc.get_element('filter') or { return error('Missing filter element') }
-
- // Parse filter
- if comp := filter_elem.get_element('comp-filter') {
- filter.comp_type = comp.attributes['name'] or { '' }
-
- // Check for time-range
- if tr := comp.get_element('time-range') {
- start := tr.attributes['start'] or { '' }
- end := tr.attributes['end'] or { '' }
- if start != '' && end != '' {
- filter.time_range = calbox.TimeRange{
- start: calbox.parse_datetime(start)!
- end: calbox.parse_datetime(end)!
- }
- }
- }
-
- // Check for property filter
- if prop := comp.get_element('prop-filter') {
- filter.prop_name = prop.attributes['name'] or { '' }
-
- // Check for text match
- if tm := prop.get_element('text-match') {
- filter.text_match = tm.text()
- }
- }
- }
-
- return filter
-}
-
-// Parses a calendar-multiget REPORT request body
-pub fn parse_calendar_multiget(body string) ![]string {
- doc := xml.parse(body) or { return error('Invalid XML') }
-
- mut hrefs := []string{}
-
- // Find href elements
- for href in doc.find_all_elements('href') {
- hrefs << href.text()
- }
-
- return hrefs
-}
-
-// Parses a free-busy-query REPORT request body
-pub fn parse_freebusy_query(body string) !calbox.TimeRange {
- doc := xml.parse(body) or { return error('Invalid XML') }
-
- // Find time-range element
- tr := doc.get_element('time-range') or { return error('Missing time-range element') }
-
- start := tr.attributes['start'] or { return error('Missing start attribute') }
- end := tr.attributes['end'] or { return error('Missing end attribute') }
-
- return calbox.TimeRange{
- start: calbox.parse_datetime(start)!
- end: calbox.parse_datetime(end)!
- }
-}
-
-// Generates XML response for MKCALENDAR
-pub fn generate_mkcalendar_response() string {
- return '\n'
-}
-
-// Generates XML response for calendar-query REPORT
-pub fn generate_calendar_query_response(objects []calbox.CalendarObject) string {
- mut response := '\n\n'
-
- for obj in objects {
- response += ' \n'
- response += ' ${obj.uid}\n'
- response += ' \n'
- response += ' \n'
- response += ' ${obj.etag}\n'
- response += ' ${obj.to_ical()}\n'
- response += ' \n'
- response += ' HTTP/1.1 200 OK\n'
- response += ' \n'
- response += ' \n'
- }
-
- response += ''
- return response
-}
-
-// Generates XML response for calendar-multiget REPORT
-pub fn generate_calendar_multiget_response(objects []calbox.CalendarObject) string {
- // Same format as calendar-query response
- return generate_calendar_query_response(objects)
-}
-
-// Generates XML response for free-busy-query REPORT
-pub fn generate_freebusy_response(ranges []calbox.TimeRange) string {
- mut response := 'BEGIN:VCALENDAR\r\n'
- response += 'VERSION:2.0\r\n'
- response += 'PRODID:-//Example Corp.//CalDAV Server//EN\r\n'
- response += 'BEGIN:VFREEBUSY\r\n'
-
- for r in ranges {
- response += 'FREEBUSY:${calbox.format_datetime_utc(r.start)}/${calbox.format_datetime_utc(r.end)}\r\n'
- }
-
- response += 'END:VFREEBUSY\r\n'
- response += 'END:VCALENDAR\r\n'
- return response
-}
diff --git a/lib/servers/contacts/carddav/specs.md b/lib/servers/contacts/carddav/specs.md
deleted file mode 100644
index ec989912..00000000
--- a/lib/servers/contacts/carddav/specs.md
+++ /dev/null
@@ -1,2363 +0,0 @@
-
-
- CardDAV: vCard Extensions to
- Web Distributed Authoring and Versioning (WebDAV)
-
-Abstract
-
- This document defines extensions to the Web Distributed Authoring and
- Versioning (WebDAV) protocol to specify a standard way of accessing,
- managing, and sharing contact information based on the vCard format.
-
-
-Daboo Standards Track [Page 3]
-
-RFC 6352 CardDAV August 2011
-
-
-1. Introduction and Overview
-
- Address books containing contact information are a key component of
- personal information management tools, such as email, calendaring and
- scheduling, and instant messaging clients. To date several protocols
- have been used for remote access to contact data, including the
- Lightweight Directory Access Protocol (LDAP) [RFC4510], Internet
- Message Support Protocol [IMSP], and Application Configuration Access
- Protocol (ACAP) [RFC2244], together with SyncML used for
- synchronization of such data.
-
- WebDAV [RFC4918] offers a number of advantages as a framework or
- basis for address book access and management. Most of these
- advantages boil down to a significant reduction in the costs of
- design, implementation, interoperability testing, and deployment.
-
- The key features of address book support with WebDAV are:
-
- 1. Ability to use multiple address books with hierarchical layout.
-
- 2. Ability to control access to individual address books and address
- entries as per WebDAV Access Control List (ACL) [RFC3744].
-
- 3. Principal collections can be used to enumerate and query other
- users on the system as per WebDAV ACL [RFC3744].
-
- 4. Server-side searching of address data, avoiding the need for
- clients to download an entire address book in order to do a quick
- address 'expansion' operation.
-
- 5. Well-defined internationalization support through WebDAV's use of
- XML.
-
- 6. Use of vCards [RFC2426] for well-defined address schema to
- enhance client interoperability.
-
- 7. Many limited clients (e.g., mobile devices) contain an HTTP stack
- that makes implementing WebDAV much easier than other protocols.
-
- The key disadvantage of address book support in WebDAV is:
-
- 8. Lack of change notification. Many of the alternative protocols
- also lack this ability. However, an extension for push
- notifications could easily be developed.
-
- vCard is a MIME directory profile aimed at encapsulating personal
- addressing and contact information about people. The specification
- of vCard was originally done by the Versit consortium, with a
-
-
-
-Daboo Standards Track [Page 4]
-
-RFC 6352 CardDAV August 2011
-
-
- subsequent 3.0 version standardized by the IETF [RFC2426]. vCard is
- in widespread use in email clients and mobile devices as a means of
- encapsulating address information for transport via email or for
- import/export and synchronization operations.
-
- An update to vCard -- vCard v4 -- is currently being developed
- [RFC6350] and is compatible with this specification.
-
-2. Conventions
-
- The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
- "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
- document are to be interpreted as described in [RFC2119].
-
- The term "protected" is used in the Conformance field of property
- definitions as defined in Section 15 of [RFC4918].
-
- This document uses XML DTD fragments ([W3C.REC-xml-20081126], Section
- 3.2) as a purely notational convention. WebDAV request and response
- bodies cannot be validated by a DTD due to the specific extensibility
- rules defined in Section 17 of [RFC4918] and due to the fact that all
- XML elements defined by that specification use the XML namespace name
- "DAV:". In particular:
-
- 1. Element names use the "DAV:" namespace.
-
- 2. Element ordering is irrelevant unless explicitly stated.
-
- 3. Extension elements (elements not already defined as valid child
- elements) may be added anywhere, except when explicitly stated
- otherwise.
-
- 4. Extension attributes (attributes not already defined as valid for
- this element) may be added anywhere, except when explicitly
- stated otherwise.
-
- The namespace "urn:ietf:params:xml:ns:carddav" is reserved for the
- XML elements defined in this specification, its revisions, and
- related CardDAV specifications. XML elements defined by individual
- implementations MUST NOT use the "urn:ietf:params:xml:ns:carddav"
- namespace, and instead should use a namespace that they control.
-
- When XML element types in the namespaces "DAV:" and
- "urn:ietf:params:xml:ns:carddav" are referenced in this document
- outside of the context of an XML fragment, the strings "DAV:" and
- "CARDDAV:" will be prefixed to the element types, respectively.
-
-
-
-
-
-Daboo Standards Track [Page 5]
-
-RFC 6352 CardDAV August 2011
-
-
- This document inherits, and sometimes extends, DTD productions from
- Section 14 of [RFC4918].
-
- Also, note that some CardDAV XML element names are identical to
- WebDAV XML element names, though their namespace differs. Care must
- be taken not to confuse the two sets of names.
-
-3. Requirements Overview
-
- This section lists what functionality is required of a CardDAV
- server. To advertise support for CardDAV, a server:
-
- o MUST support vCard v3 [RFC2426] as a media type for the address
- object resource format;
-
- o MUST support WebDAV Class 3 [RFC4918];
-
- o MUST support WebDAV ACL [RFC3744];
-
- o MUST support secure transport as defined in [RFC2818] using
- Transport Layer Security (TLS) [RFC5246] and using the certificate
- validation procedures described in [RFC5280];
-
- o MUST support ETags [RFC2616] with additional requirements
- specified in Section 6.3.2.3 of this document;
-
- o MUST support all address book reports defined in Section 8 of this
- document; and
-
- o MUST advertise support on all address book collections and address
- object resources for the address book reports in the
- DAV:supported-report-set property, as defined in Versioning
- Extensions to WebDAV [RFC3253].
-
- In addition, a server:
-
- o SHOULD support vCard v4 [RFC6350] as a media type for the address
- object resource format;
-
- o SHOULD support the extended MKCOL method [RFC5689] to create
- address book collections as defined in Section 6.3.1 of this
- document.
-
- o SHOULD support the DAV:current-user-principal-URL property as
- defined in [RFC5397] to give clients a fast way to locate user
- principals.
-
-
-
-
-
-Daboo Standards Track [Page 6]
-
-RFC 6352 CardDAV August 2011
-
-
-4. Address Book Data Model
-
- As a brief overview, a CardDAV address book is modeled as a WebDAV
- collection with a well-defined structure; each of these address book
- collections contains a number of resources representing address
- objects as their direct child resources. Each resource representing
- an address object is called an "address object resource". Each
- address object resource and each address book collection can be
- individually locked and have individual WebDAV properties.
- Requirements derived from this model are provided in Sections 5.1 and
- 5.2.
-
-4.1. Address Book Server
-
- A CardDAV server is an address-aware engine combined with a WebDAV
- server. The server may include address data in some parts of its URL
- namespace and non-address data in other parts.
-
- A WebDAV server can advertise itself as a CardDAV server if it
- supports the functionality defined in this specification at any point
- within the root of its repository. That might mean that address data
- is spread throughout the repository and mixed with non-address data
- in nearby collections (e.g., address data may be found in /lisa/
- addressbook/ as well as in /bernard/addressbook/, and non-address
- data in /lisa/calendars/). Or, it might mean that address data can
- be found only in certain sections of the repository (e.g.,
- /addressbooks/user/). Address book features are only required in the
- repository sections that are or contain address objects. So, a
- repository confining address data to the /carddav/ collection would
- only need to support the CardDAV required features within that
- collection.
-
- The CardDAV server is the canonical location for address data and
- state information. Clients may submit requests to change data or
- download data. Clients may store address objects offline and attempt
- to synchronize at a later time. Address data on the server can
- change between the time of last synchronization and when attempting
- an update, as address book collections may be shared and accessible
- via multiple clients. Entity tags and locking help this work.
-
-5. Address Book Resources
-
-5.1. Address Object Resources
-
- This specification uses vCard as the default format for address or
- contact information being stored on the server. However, this
- specification does allow other formats for address data provided that
- the server advertises support for those additional formats as
-
-
-
-Daboo Standards Track [Page 7]
-
-RFC 6352 CardDAV August 2011
-
-
- described below. The requirements in this section pertain to vCard
- address data or formats that follow the semantics of vCard data.
-
- Address object resources contained in address book collections MUST
- contain a single vCard component only.
-
- vCard components in an address book collection MUST have a UID
- property value that MUST be unique in the scope of the address book
- collection in which it is contained.
-
-5.1.1. Data Type Conversion
-
- Servers might support more than one primary media type for address
- object resources, for example, vCard v3.0 and vCard v4.0. In such
- cases, servers have to accept all media types that they advertise via
- the CARDDAV:supported-address-data WebDAV property (see
- Section 6.2.2).
-
- However, clients can use standard HTTP content negotiation behavior
- (the Accept request header defined in Section 14.1 of [RFC2616]) to
- request that an address object resource's data be returned in a
- specific media type format. For example, a client merely capable of
- handling vCard v3.0 would only want to have address object resources
- returned in v3.0 format.
-
- Additionally, REPORT requests, defined later in this specification,
- allow for the return of address object resource data within an XML
- response body. Again, the client can use content negotiation to
- request that data be returned in a specific media type by specifying
- appropriate attributes on the CARDDAV:address-data XML element used
- in the request body (see Section 10.4).
-
- In some cases, it might not be possible for a server to convert from
- one media type to another. When that happens, the server MUST return
- the CARDDAV:supported-address-data-conversion precondition (see
- below) in the response body (when the failure to convert applies to
- the entire response) or use that same precondition code in the
- DAV:response XML element in the response for the targeted address
- object resource when one of the REPORTs defined below is used. See
- Section 8.7.2 for an example of this.
-
-5.1.1.1. Additional Precondition for GET
-
- This specification creates additional preconditions for the GET
- method.
-
-
-
-
-
-
-Daboo Standards Track [Page 8]
-
-RFC 6352 CardDAV August 2011
-
-
- The new precondition is:
-
- (CARDDAV:supported-address-data-conversion): The resource targeted
- by the GET request can be converted to the media type specified in
- the Accept request header included with the request.
-
-5.2. Address Book Collections
-
- Address book collections appear to clients as a WebDAV collection
- resource, identified by a URL. An address book collection MUST
- report the DAV:collection and CARDDAV:addressbook XML elements in the
- value of the DAV:resourcetype property. The element type declaration
- for CARDDAV:addressbook is:
-
-
-
- An address book collection can be created through provisioning (e.g.,
- automatically created when a user's account is provisioned), or it
- can be created with the extended MKCOL method (see Section 6.3.1).
- This can be used by a user to create additional address books (e.g.,
- "soccer team members") or for users to share an address book (e.g.,
- "sales team contacts"). However, note that this document doesn't
- define what extra address book collections are for. Users must rely
- on non-standard cues to find out what an address book collection is
- for, or use the CARDDAV:addressbook-description property defined in
- Section 6.2.1 to provide such a cue.
-
- The following restrictions are applied to the resources within an
- address book collection:
-
- a. Address book collections MUST only contain address object
- resources and collections that are not address book collections.
- That is, the only "top-level" non-collection resources allowed in
- an address book collection are address object resources. This
- ensures that address book clients do not have to deal with non-
- address data in an address book collection, though they do have
- to distinguish between address object resources and collections
- when using standard WebDAV techniques to examine the contents of
- a collection.
-
- b. Collections contained in address book collections MUST NOT
- contain address book collections at any depth. That is,
- "nesting" of address book collections within other address book
- collections at any depth is not allowed. This specification does
- not define how collections contained in an address book
- collection are used or how they relate to any address object
- resources contained in the address book collection.
-
-
-
-
-Daboo Standards Track [Page 9]
-
-RFC 6352 CardDAV August 2011
-
-
- Multiple address book collections MAY be children of the same
- collection.
-
-6. Address Book Feature
-
-6.1. Address Book Support
-
- A server supporting the features described in this document MUST
- include "addressbook" as a field in the DAV response header from an
- OPTIONS request on any resource that supports any address book
- properties, reports, or methods. A value of "addressbook" in the DAV
- response header MUST indicate that the server supports all MUST level
- requirements and REQUIRED features specified in this document.
-
-6.1.1. Example: Using OPTIONS for the Discovery of Support for CardDAV
-
- >> Request <<
-
- OPTIONS /addressbooks/users/ HTTP/1.1
- Host: addressbook.example.com
-
- >> Response <<
-
- HTTP/1.1 200 OK
- Allow: OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, COPY, MOVE
- Allow: MKCOL, PROPFIND, PROPPATCH, LOCK, UNLOCK, REPORT, ACL
- DAV: 1, 2, 3, access-control, addressbook
- DAV: extended-mkcol
- Date: Sat, 11 Nov 2006 09:32:12 GMT
- Content-Length: 0
-
- In this example, the OPTIONS response indicates that the server
- supports CardDAV in this namespace; therefore, the '/addressbooks/
- users/' collection may be used as a parent for address book
- collections as the extended MKCOL method is available and as a
- possible target for REPORT requests for address book reports.
-
-6.2. Address Book Properties
-
-6.2.1. CARDDAV:addressbook-description Property
-
- Name: addressbook-description
-
- Namespace: urn:ietf:params:xml:ns:carddav
-
- Purpose: Provides a human-readable description of the address book
- collection.
-
-
-
-
-Daboo Standards Track [Page 10]
-
-RFC 6352 CardDAV August 2011
-
-
- Value: Any text.
-
- Protected: SHOULD NOT be protected so that users can specify a
- description.
-
- COPY/MOVE behavior: This property value SHOULD be preserved in COPY
- and MOVE operations.
-
- allprop behavior: SHOULD NOT be returned by a PROPFIND DAV:allprop
- request.
-
- Description: This property contains a description of the address
- book collection that is suitable for presentation to a user. The
- xml:lang attribute can be used to add a language tag for the value
- of this property.
-
- Definition:
-
-
-
-
- Example:
-
- Adresses de Oliver Daboo
-
-6.2.2. CARDDAV:supported-address-data Property
-
- Name: supported-address-data
-
- Namespace: urn:ietf:params:xml:ns:carddav
-
- Purpose: Specifies what media types are allowed for address object
- resources in an address book collection.
-
- Protected: MUST be protected as it indicates the level of support
- provided by the server.
-
- COPY/MOVE behavior: This property value MUST be preserved in COPY
- and MOVE operations.
-
- allprop behavior: SHOULD NOT be returned by a PROPFIND DAV:allprop
- request.
-
- Description: The CARDDAV:supported-address-data property is used to
- specify the media type supported for the address object resources
- contained in a given address book collection (e.g., vCard version
-
-
-
-Daboo Standards Track [Page 11]
-
-RFC 6352 CardDAV August 2011
-
-
- 3.0). Any attempt by the client to store address object resources
- with a media type not listed in this property MUST result in an
- error, with the CARDDAV:supported-address-data precondition
- (Section 6.3.2.1) being violated. In the absence of this
- property, the server MUST only accept data with the media type
- "text/vcard" and vCard version 3.0, and clients can assume that is
- all the server will accept.
-
- Definition:
-
-
-
-
-
-
-
-
- Example:
-
-
-
-
-
-6.2.3. CARDDAV:max-resource-size Property
-
- Name: max-resource-size
-
- Namespace: urn:ietf:params:xml:ns:carddav
-
- Purpose: Provides a numeric value indicating the maximum size in
- octets of a resource that the server is willing to accept when an
- address object resource is stored in an address book collection.
-
- Value: Any text representing a numeric value.
-
- Protected: MUST be protected as it indicates limits provided by the
- server.
-
- COPY/MOVE behavior: This property value MUST be preserved in COPY
- and MOVE operations.
-
- allprop behavior: SHOULD NOT be returned by a PROPFIND DAV:allprop
- request.
-
-
-
-
-
-
-Daboo Standards Track [Page 12]
-
-RFC 6352 CardDAV August 2011
-
-
- Description: The CARDDAV:max-resource-size is used to specify a
- numeric value that represents the maximum size in octets that the
- server is willing to accept when an address object resource is
- stored in an address book collection. Any attempt to store an
- address book object resource exceeding this size MUST result in an
- error, with the CARDDAV:max-resource-size precondition
- (Section 6.3.2.1) being violated. In the absence of this
- property, the client can assume that the server will allow storing
- a resource of any reasonable size.
-
- Definition:
-
-
-
-
- Example:
-
- 102400
-
-6.3. Creating Resources
-
- Address book collections and address object resources may be created
- by either a CardDAV client or the CardDAV server. This specification
- defines restrictions and a data model that both clients and servers
- MUST adhere to when manipulating such address data.
-
-6.3.1. Extended MKCOL Method
-
- An HTTP request using the extended MKCOL method [RFC5689] can be used
- to create a new address book collection resource. A server MAY
- restrict address book collection creation to particular collections.
-
- To create an address book, the client sends an extended MKCOL request
- to the server and in the body of the request sets the
- DAV:resourcetype property to the resource type for an address book
- collection as defined in Section 5.2.
-
- Support for creating address books on the server is only RECOMMENDED
- and not REQUIRED because some address book stores only support one
- address book per user (or principal), and those are typically pre-
- created for each account. However, servers and clients are strongly
- encouraged to support address book creation whenever possible to
- allow users to create multiple address book collections to help
- organize their data better.
-
-
-
-
-
-
-Daboo Standards Track [Page 13]
-
-RFC 6352 CardDAV August 2011
-
-
- The DAV:displayname property can be used for a human-readable name of
- the address book. Clients can either specify the value of the
- DAV:displayname property in the request body of the extended MKCOL
- request or, alternatively, issue a PROPPATCH request to change the
- DAV:displayname property to the appropriate value immediately after
- using the extended MKCOL request. When displaying address book
- collections to users, clients SHOULD check the DAV:displayname
- property and use that value as the name of the address book. In the
- event that the DAV:displayname property is not set, the client MAY
- use the last part of the address book collection URI as the name;
- however, that path segment may be "opaque" and not represent any
- meaningful human-readable text.
-
-6.3.1.1. Example - Successful MKCOL Request
-
- This example creates an address book collection called /home/lisa/
- addressbook/ on the server addressbook.example.com with specific
- values for the properties DAV:resourcetype, DAV:displayname, and
- CARDDAV:addressbook-description.
-
- >> Request <<
-
- MKCOL /home/lisa/addressbook/ HTTP/1.1
- Host: addressbook.example.com
- Content-Type: text/xml; charset="utf-8"
- Content-Length: xxx
-
-
-
-
-
-
-
-
-
- Lisa's Contacts
- My primary address book.
-
-
-
-
-
-
-
-
-
-
-
-
-Daboo Standards Track [Page 14]
-
-RFC 6352 CardDAV August 2011
-
-
- >> Response <<
-
- HTTP/1.1 201 Created
- Cache-Control: no-cache
- Date: Sat, 11 Nov 2006 09:32:12 GMT
- Content-Type: application/xml; charset="utf-8"
- Content-Length: xxxx
-
-
-
-
-
-
-
-
-
- HTTP/1.1 200 OK
-
-
-
-6.3.2. Creating Address Object Resources
-
- Clients populate address book collections with address object
- resources. The URL for each address object resource is entirely
- arbitrary and does not need to bear a specific relationship (but
- might) to the address object resource's vCard properties or other
- metadata. New address object resources MUST be created with a PUT
- request targeted at an unmapped URI. A PUT request targeted at a
- mapped URI updates an existing address object resource.
-
- When servers create new resources, it's not hard for the server to
- choose a unique URL. It's slightly tougher for clients, because a
- client might not want to examine all resources in the collection and
- might not want to lock the entire collection to ensure that a new one
- isn't created with a name collision. However, there is an HTTP
- feature to mitigate this. If the client intends to create a new
- address resource, the client SHOULD use the HTTP header "If-None-
- Match: *" on the PUT request. The Request-URI on the PUT request
- MUST include the target collection, where the resource is to be
- created, plus the name of the resource in the last path segment. The
- "If-None-Match" header ensures that the client will not inadvertently
- overwrite an existing resource even if the last path segment turned
- out to already be used.
-
-
-
-
-
-
-
-Daboo Standards Track [Page 15]
-
-RFC 6352 CardDAV August 2011
-
-
- >> Request <<
-
- PUT /lisa/addressbook/newvcard.vcf HTTP/1.1
- If-None-Match: *
- Host: addressbook.example.com
- Content-Type: text/vcard
- Content-Length: xxx
-
- BEGIN:VCARD
- VERSION:3.0
- FN:Cyrus Daboo
- N:Daboo;Cyrus
- ADR;TYPE=POSTAL:;2822 Email HQ;Suite 2821;RFCVille;PA;15213;USA
- EMAIL;TYPE=INTERNET,PREF:cyrus@example.com
- NICKNAME:me
- NOTE:Example VCard.
- ORG:Self Employed
- TEL;TYPE=WORK,VOICE:412 605 0499
- TEL;TYPE=FAX:412 605 0705
- URL:http://www.example.com
- UID:1234-5678-9000-1
- END:VCARD
-
- >> Response <<
-
- HTTP/1.1 201 Created
- Date: Thu, 02 Sep 2004 16:53:32 GMT
- Content-Length: 0
- ETag: "123456789-000-111"
-
- The request to change an existing address object resource without
- overwriting a change made on the server uses a specific ETag in an
- "If-Match" header, rather than the "If-None-Match" header.
-
- File names for vCards are commonly suffixed by ".vcf", and clients
- may choose to use the same convention for URLs.
-
-6.3.2.1. Additional Preconditions for PUT, COPY, and MOVE
-
- This specification creates additional preconditions for the PUT,
- COPY, and MOVE methods. These preconditions apply:
-
- o When a PUT operation of an address object resource into an address
- book collection occurs.
-
- o When a COPY or MOVE operation of an address object resource into
- an address book collection occurs.
-
-
-
-
-Daboo Standards Track [Page 16]
-
-RFC 6352 CardDAV August 2011
-
-
- The new preconditions are:
-
- (CARDDAV:supported-address-data): The resource submitted in the
- PUT request, or targeted by a COPY or MOVE request, MUST be a
- supported media type (i.e., vCard) for address object resources.
-
- (CARDDAV:valid-address-data): The resource submitted in the PUT
- request, or targeted by a COPY or MOVE request, MUST be valid data
- for the media type being specified (i.e., MUST contain valid vCard
- data).
-
- (CARDDAV:no-uid-conflict): The resource submitted in the PUT
- request, or targeted by a COPY or MOVE request, MUST NOT specify a
- vCard UID property value already in use in the targeted address
- book collection or overwrite an existing address object resource
- with one that has a different UID property value. Servers SHOULD
- report the URL of the resource that is already making use of the
- same UID property value in the DAV:href element.
-
-
-
- (CARDDAV:addressbook-collection-location-ok): In a COPY or MOVE
- request, when the Request-URI is an address book collection, the
- URI targeted by the Destination HTTP Request header MUST identify
- a location where an address book collection can be created.
-
- (CARDDAV:max-resource-size): The resource submitted in the PUT
- request, or targeted by a COPY or MOVE request, MUST have a size
- in octets less than or equal to the value of the
- CARDDAV:max-resource-size property value (Section 6.2.3) on the
- address book collection where the resource will be stored.
-
-6.3.2.2. Non-Standard vCard Properties and Parameters
-
- vCard provides a "standard mechanism for doing non-standard things".
- This extension support allows implementers to make use of non-
- standard vCard properties and parameters whose names are prefixed
- with the text "X-".
-
- Servers MUST support the use of non-standard properties and
- parameters in address object resources stored via the PUT method.
-
- Servers may need to enforce rules for their own "private" properties
- or parameters, so servers MAY reject any attempt by the client to
- change those or use values for those outside of any restrictions the
- server may have. A server SHOULD ensure that any "private"
-
-
-
-
-
-Daboo Standards Track [Page 17]
-
-RFC 6352 CardDAV August 2011
-
-
- properties or parameters it uses follow the convention of including a
- vendor ID in the "X-" name, as described in Section 3.8 of [RFC2426],
- e.g., "X-ABC-PRIVATE".
-
-6.3.2.3. Address Object Resource Entity Tag
-
- The DAV:getetag property MUST be defined and set to a strong entity
- tag on all address object resources.
-
- A response to a GET request targeted at an address object resource
- MUST contain an ETag response header field indicating the current
- value of the strong entity tag of the address object resource.
-
- Servers SHOULD return a strong entity tag (ETag header) in a PUT
- response when the stored address object resource is equivalent by
- octet equality to the address object resource submitted in the body
- of the PUT request. This allows clients to reliably use the returned
- strong entity tag for data synchronization purposes. For instance,
- the client can do a PROPFIND request on the stored address object
- resource, have the DAV:getetag property returned, compare that value
- with the strong entity tag it received on the PUT response, and know
- that if they are equal, then the address object resource on the
- server has not been changed.
-
- In the case where the data stored by a server as a result of a PUT
- request is not equivalent by octet equality to the submitted address
- object resource, the behavior of the ETag response header is not
- specified here, with the exception that a strong entity tag MUST NOT
- be returned in the response. As a result, a client may need to
- retrieve the modified address object resource (and ETag) as a basis
- for further changes, rather than use the address object resource it
- had sent with the PUT request.
-
-7. Address Book Access Control
-
- CardDAV servers MUST support and adhere to the requirements of WebDAV
- ACL [RFC3744]. WebDAV ACL provides a framework for an extensible set
- of privileges that can be applied to WebDAV collections and ordinary
- resources.
-
-7.1. Additional Principal Properties
-
- This section defines additional properties for WebDAV principal
- resources as defined in [RFC3744].
-
-
-
-
-
-
-
-Daboo Standards Track [Page 18]
-
-RFC 6352 CardDAV August 2011
-
-
-7.1.1. CARDDAV:addressbook-home-set Property
-
- Name: addressbook-home-set
-
- Namespace: urn:ietf:params:xml:ns:carddav
-
- Purpose: Identifies the URL of any WebDAV collections that contain
- address book collections owned by the associated principal
- resource.
-
- Protected: MAY be protected if the server has fixed locations in
- which address books are created.
-
- COPY/MOVE behavior: This property value MUST be preserved in COPY
- and MOVE operations.
-
- allprop behavior: SHOULD NOT be returned by a PROPFIND DAV:allprop
- request.
-
- Description: The CARDDAV:addressbook-home-set property is meant to
- allow users to easily find the address book collections owned by
- the principal. Typically, users will group all the address book
- collections that they own under a common collection. This
- property specifies the URL of collections that are either address
- book collections or ordinary collections that have child or
- descendant address book collections owned by the principal.
-
- Definition:
-
-
-
- Example:
-
-
- /bernard/addresses/
-
-
-7.1.2. CARDDAV:principal-address Property
-
- Name: principal-address
-
- Namespace: urn:ietf:params:xml:ns:carddav
-
- Purpose: Identifies the URL of an address object resource that
- corresponds to the user represented by the principal.
-
-
-
-
-
-Daboo Standards Track [Page 19]
-
-RFC 6352 CardDAV August 2011
-
-
- Protected: MAY be protected if the server provides a fixed location
- for principal addresses.
-
- COPY/MOVE behavior: This property value MUST be preserved in COPY
- and MOVE operations.
-
- allprop behavior: SHOULD NOT be returned by a PROPFIND DAV:allprop
- request.
-
- Description: The CARDDAV:principal-address property is meant to
- allow users to easily find contact information for users
- represented by principals on the system. This property specifies
- the URL of the resource containing the corresponding contact
- information. The resource could be an address object resource in
- an address book collection, or it could be a resource in a
- "regular" collection.
-
- Definition:
-
-
-
- Example:
-
-
- /system/cyrus.vcf
-
-
-8. Address Book Reports
-
- This section defines the reports that CardDAV servers MUST support on
- address book collections and address object resources.
-
- CardDAV servers MUST advertise support for these reports on all
- address book collections and address object resources with the
- DAV:supported-report-set property defined in Section 3.1.5 of
- [RFC3253]. CardDAV servers MAY also advertise support for these
- reports on ordinary collections.
-
- Some of these reports allow address data (from possibly multiple
- resources) to be returned.
-
-8.1. REPORT Method
-
- The REPORT method (defined in Section 3.6 of [RFC3253]) provides an
- extensible mechanism for obtaining information about a resource.
- Unlike the PROPFIND method, which returns the value of one or more
- named properties, the REPORT method can involve more complex
-
-
-
-Daboo Standards Track [Page 20]
-
-RFC 6352 CardDAV August 2011
-
-
- processing. REPORT is valuable in cases where the server has access
- to all of the information needed to perform the complex request (such
- as a query), and where it would require multiple requests for the
- client to retrieve the information needed to perform the same
- request.
-
- A server that supports this specification MUST support the
- DAV:expand-property report (defined in Section 3.8 of [RFC3253]).
-
-8.2. Ordinary Collections
-
- Servers MAY support the reports defined in this document on ordinary
- collections (collections that are not address book collections) in
- addition to address book collections or address object resources. In
- computing responses to the reports on ordinary collections, servers
- MUST only consider address object resources contained in address book
- collections that are targeted by the REPORT based on the value of the
- Depth request header.
-
-8.3. Searching Text: Collations
-
- Some of the reports defined in this section do text matches of
- character strings provided by the client and compared to stored
- address data. Since vCard data is by default encoded in the UTF-8
- charset and may include characters outside of the US-ASCII charset
- range in some property and parameter values, there is a need to
- ensure that text matching follows well-defined rules.
-
- To deal with this, this specification makes use of the IANA Collation
- Registry defined in [RFC4790] to specify collations that may be used
- to carry out the text comparison operations with a well-defined rule.
-
- Collations supported by the server MUST support "equality" and
- "substring" match operations as per [RFC4790], Section 4.2, including
- the "prefix" and "suffix" options for "substring" matching. CardDAV
- uses these match options for "equals", "contains", "starts-with", and
- "ends-with" match operations.
-
- CardDAV servers are REQUIRED to support the "i;ascii-casemap"
- [RFC4790] and "i;unicode-casemap" [RFC5051] collations and MAY
- support other collations.
-
- Servers MUST advertise the set of collations that they support via
- the CARDDAV:supported-collation-set property defined on any resource
- that supports reports that use collations.
-
-
-
-
-
-
-Daboo Standards Track [Page 21]
-
-RFC 6352 CardDAV August 2011
-
-
- In the absence of a collation explicitly specified by the client, or
- if the client specifies the "default" collation identifier (as
- defined in [RFC4790], Section 3.1), the server MUST default to using
- "i;unicode-casemap" as the collation.
-
- Wildcards (as defined in [RFC4790], Section 3.2) MUST NOT be used in
- the collation identifier.
-
- If the client chooses a collation not supported by the server, the
- server MUST respond with a CARDDAV:supported-collation precondition
- error response.
-
-8.3.1. CARDDAV:supported-collation-set Property
-
- Name: supported-collation-set
-
- Namespace: urn:ietf:params:xml:ns:carddav
-
- Purpose: Identifies the set of collations supported by the server
- for text matching operations.
-
- Protected: MUST be protected as it indicates support provided by the
- server.
-
- COPY/MOVE behavior: This property value MUST be preserved in COPY
- and MOVE operations.
-
- allprop behavior: SHOULD NOT be returned by a PROPFIND DAV:allprop
- request.
-
- Description: The CARDDAV:supported-collation-set property contains
- two or more CARDDAV:supported-collation elements that specify the
- identifiers of the collations supported by the server.
-
- Definition:
-
-
-
-
-
-
-
-
-
-
-
-
-Daboo Standards Track [Page 22]
-
-RFC 6352 CardDAV August 2011
-
-
- Example:
-
-
- i;ascii-casemap
- i;octet
- i;unicode-casemap
-
-
-8.4. Partial Retrieval
-
- Some address book reports defined in this document allow partial
- retrieval of address object resources. A CardDAV client can specify
- what information to return in the body of an address book REPORT
- request.
-
- A CardDAV client can request particular WebDAV property values, all
- WebDAV property values, or a list of the names of the resource's
- WebDAV properties. A CardDAV client can also request address data to
- be returned and whether all vCard properties should be returned or
- only particular ones. See CARDDAV:address-data in Section 10.4.
-
-8.5. Non-Standard Properties and Parameters
-
- Servers MUST support the use of non-standard vCard property or
- parameter names in the CARDDAV:address-data XML element in address
- book REPORT requests to allow clients to request that non-standard
- properties and parameters be returned in the address data provided in
- the response.
-
- Servers MAY support the use of non-standard vCard property or
- parameter names in the CARDDAV:prop-filter and CARDDAV:param-filter
- XML elements specified in the CARDDAV:filter XML element of address
- book REPORT requests.
-
- Servers MUST fail with the CARDDAV:supported-filter precondition if
- an address book REPORT request uses a CARDDAV:prop-filter or
- CARDDAV:param-filter XML element that makes reference to a non-
- standard vCard property or parameter name on which the server does
- not support queries.
-
-8.6. CARDDAV:addressbook-query Report
-
- The CARDDAV:addressbook-query REPORT performs a search for all
- address object resources that match a specified filter. The response
- of this report will contain all the WebDAV properties and address
- object resource data specified in the request. In the case of the
-
-
-
-
-Daboo Standards Track [Page 23]
-
-RFC 6352 CardDAV August 2011
-
-
- CARDDAV:address-data XML element, one can explicitly specify the
- vCard properties that should be returned in the address object
- resource data that matches the filter.
-
- The format of this report is modeled on the PROPFIND method. The
- request and response bodies of the CARDDAV:addressbook-query report
- use XML elements that are also used by PROPFIND. In particular, the
- request can include XML elements to request WebDAV properties to be
- returned. When that occurs, the response should follow the same
- behavior as PROPFIND with respect to the DAV:multistatus response
- elements used to return specific WebDAV property results. For
- instance, a request to retrieve the value of a WebDAV property that
- does not exist is an error and MUST be noted with a response XML
- element that contains a 404 (Not Found) status value.
-
- Support for the CARDDAV:addressbook-query REPORT is REQUIRED.
-
- Marshalling:
-
- The request body MUST be a CARDDAV:addressbook-query XML element
- as defined in Section 10.3.
-
- The request MUST include a Depth header. The scope of the query
- is determined by the value of the Depth header. For example, to
- query all address object resources in an address book collection,
- the REPORT would use the address book collection as the Request-
- URI and specify a Depth of 1 or infinity.
-
- The response body for a successful request MUST be a
- DAV:multistatus XML element (i.e., the response uses the same
- format as the response for PROPFIND). In the case where there are
- no response elements, the returned DAV:multistatus XML element is
- empty.
-
- The response body for a successful CARDDAV:addressbook-query
- REPORT request MUST contain a DAV:response element for each
- address object that matched the search filter. Address data is
- returned in the CARDDAV:address-data XML element inside the
- DAV:propstat XML element.
-
- Preconditions:
-
- (CARDDAV:supported-address-data): The attributes "content-type"
- and "version" of the CARDDAV:address-data XML element (see
- Section 10.4) specify a media type supported by the server for
- address object resources.
-
-
-
-
-
-Daboo Standards Track [Page 24]
-
-RFC 6352 CardDAV August 2011
-
-
- (CARDDAV:supported-filter): The CARDDAV:prop-filter (see
- Section 10.5.1) and CARDDAV:param-filter (see Section 10.5.2) XML
- elements used in the CARDDAV:filter XML element (see Section 10.5)
- in the REPORT request only make reference to vCard properties and
- parameters for which queries are supported by the server. That
- is, if the CARDDAV:filter element attempts to reference an
- unsupported vCard property or parameter, this precondition is
- violated. A server SHOULD report the CARDDAV:prop-filter or
- CARDDAV:param-filter for which it does not provide support.
-
-
-
- (CARDDAV:supported-collation): Any XML attribute specifying a
- collation MUST specify a collation supported by the server as
- described in Section 8.3.
-
- Postconditions:
-
- (DAV:number-of-matches-within-limits): The number of matching
- address object resources must fall within server-specific,
- predefined limits. For example, this condition might be triggered
- if a search specification would cause the return of an extremely
- large number of responses.
-
-8.6.1. Limiting Results
-
- A client can limit the number of results returned by the server
- through use of the CARDDAV:limit element in the request body. This
- is useful when clients are only interested in a few matches or only
- have limited space to display results to users and thus don't need
- the overhead of receiving more than that. When the results are
- truncated by the server, the server MUST follow the rules below for
- indicating a result set truncation to the client.
-
-8.6.2. Truncation of Results
-
- A server MAY limit the number of resources in a response, for
- example, to limit the amount of work expended in processing a query,
- or as the result of an explicit limit set by the client. If the
- result set is truncated because of such a limit, the response MUST
- use status code 207 (Multi-Status), return a DAV:multistatus response
- body, and indicate a status of 507 (Insufficient Storage) for the
- Request-URI. That DAV:response element SHOULD include a DAV:error
- element with the DAV:number-of-matches-within-limits precondition, as
- defined in [RFC3744], Section 9.2.
-
-
-
-
-
-Daboo Standards Track [Page 25]
-
-RFC 6352 CardDAV August 2011
-
-
- The server SHOULD also include the partial results in additional
- DAV:response elements. If a client-requested limit is being applied,
- the 507 response for the Request-URI MUST NOT be included in
- calculating the limit (e.g., if the client requests that only a
- single result be returned, and multiple matches are present, then the
- DAV:multistatus response will include one DAV:response for the
- matching resource and one DAV:response for the 507 status on the
- Request-URI).
-
-8.6.3. Example: Partial Retrieval of vCards Matching NICKNAME
-
- In this example, the client requests that the server search for
- address object resources that contain a NICKNAME property whose value
- equals some specific text and return specific vCard properties for
- those vCards found. In addition, the DAV:getetag property is also
- requested and returned as part of the response.
-
- >> Request <<
-
- REPORT /home/bernard/addressbook/ HTTP/1.1
- Host: addressbook.example.com
- Depth: 1
- Content-Type: text/xml; charset="utf-8"
- Content-Length: xxxx
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- me
-
-
-
-
-
-
-
-
-Daboo Standards Track [Page 26]
-
-RFC 6352 CardDAV August 2011
-
-
- >> Response <<
-
- HTTP/1.1 207 Multi-Status
- Date: Sat, 11 Nov 2006 09:32:12 GMT
- Content-Type: text/xml; charset="utf-8"
- Content-Length: xxxx
-
-
-
-
- /home/bernard/addressbook/v102.vcf
-
-
- "23ba4d-ff11fb"
- BEGIN:VCARD
- VERSION:3.0
- NICKNAME:me
- UID:34222-232@example.com
- FN:Cyrus Daboo
- EMAIL:daboo@example.com
- END:VCARD
-
-
- HTTP/1.1 200 OK
-
-
-
-
-8.6.4. Example: Partial Retrieval of vCards Matching a Full Name or
- Email Address
-
- In this example, the client requests that the server search for
- address object resources that contain a FN property whose value
- contains some specific text or that contain an EMAIL property whose
- value contains other text and return specific vCard properties for
- those vCards found. In addition, the DAV:getetag property is also
- requested and returned as part of the response.
-
- >> Request <<
-
- REPORT /home/bernard/addressbook/ HTTP/1.1
- Host: addressbook.example.com
- Depth: 1
- Content-Type: text/xml; charset="utf-8"
- Content-Length: xxxx
-
-
-
-
-
-Daboo Standards Track [Page 27]
-
-RFC 6352 CardDAV August 2011
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- daboo
-
-
- daboo
-
-
-
-
- >> Response <<
-
- HTTP/1.1 207 Multi-Status
- Date: Sat, 11 Nov 2006 09:32:12 GMT
- Content-Type: text/xml; charset="utf-8"
- Content-Length: xxxx
-
-
-
-
- /home/bernard/addressbook/v102.vcf
-
-
- "23ba4d-ff11fb"
- BEGIN:VCARD
- VERSION:3.0
- NICKNAME:me
- UID:34222-232@example.com
- FN:David Boo
- EMAIL:daboo@example.com
-
-
-
-Daboo Standards Track [Page 28]
-
-RFC 6352 CardDAV August 2011
-
-
- END:VCARD
-
-
- HTTP/1.1 200 OK
-
-
-
- /home/bernard/addressbook/v104.vcf
-
-
- "23ba4d-ff11fc"
- BEGIN:VCARD
- VERSION:3.0
- NICKNAME:oliver
- UID:34222-23222@example.com
- FN:Oliver Daboo
- EMAIL:oliver@example.com
- END:VCARD
-
-
- HTTP/1.1 200 OK
-
-
-
-
-8.6.5. Example: Truncated Results
-
- In this example, the client requests that the server search for
- address object resources that contain a FN property whose value
- contains some specific text and return the DAV:getetag property for
- two results only. The server response includes a 507 status for the
- Request-URI indicating that there were more than two resources that
- matched the query, but that the server truncated the result set as
- requested by the client.
-
- >> Request <<
-
- REPORT /home/bernard/addressbook/ HTTP/1.1
- Host: addressbook.example.com
- Depth: 1
- Content-Type: text/xml; charset="utf-8"
- Content-Length: xxxx
-
-
-
-
-
-
-
-
-Daboo Standards Track [Page 29]
-
-RFC 6352 CardDAV August 2011
-
-
-
-
-
-
-
- daboo
-
-
-
- 2
-
-
-
- >> Response <<
-
- HTTP/1.1 207 Multi-Status
- Date: Sat, 11 Nov 2006 09:32:12 GMT
- Content-Type: text/xml; charset="utf-8"
- Content-Length: xxxx
-
-
-
-
- /home/bernard/addressbook/
- HTTP/1.1 507 Insufficient Storage
-
-
- Only two matching records were returned
-
-
-
- /home/bernard/addressbook/v102.vcf
-
-
- "23ba4d-ff11fb"
-
- HTTP/1.1 200 OK
-
-
-
- /home/bernard/addressbook/v104.vcf
-
-
- "23ba4d-ff11fc"
-
-
-
-
-Daboo Standards Track [Page 30]
-
-RFC 6352 CardDAV August 2011
-
-
- HTTP/1.1 200 OK
-
-
-
-
-8.7. CARDDAV:addressbook-multiget Report
-
- The CARDDAV:addressbook-multiget REPORT is used to retrieve specific
- address object resources from within a collection, if the Request-URI
- is a collection, or to retrieve a specific address object resource,
- if the Request-URI is an address object resource. This report is
- similar to the CARDDAV:addressbook-query REPORT (see Section 8.6),
- except that it takes a list of DAV:href elements instead of a
- CARDDAV:filter element to determine which address object resources to
- return.
-
- Support for the addressbook-multiget REPORT is REQUIRED.
-
- Marshalling:
-
- The request body MUST be a CARDDAV:addressbook-multiget XML
- element (see Section 10.7), which MUST contain at least one
- DAV:href XML element and one optional CARDDAV:address-data element
- as defined in Section 10.4. If DAV:href elements are present, the
- scope of the request is the set of resources identified by these
- elements, which all need to be members (not necessarily internal
- members) of the resource identified by the Request-URI.
- Otherwise, the scope is the resource identified by the Request-URI
- itself.
-
- The request MUST include a Depth: 0 header; however, the actual
- scope of the REPORT is determined as described above.
-
- The response body for a successful request MUST be a
- DAV:multistatus XML element.
-
- The response body for a successful CARDDAV:addressbook-multiget
- REPORT request MUST contain a DAV:response element for each
- address object resource referenced by the provided set of DAV:href
- elements. Address data is returned in the CARDDAV:address-data
- element inside the DAV:prop element.
-
- In the case of an error accessing any of the provided DAV:href
- resources, the server MUST return the appropriate error status
- code in the DAV:status element of the corresponding DAV:response
- element.
-
-
-
-
-
-Daboo Standards Track [Page 31]
-
-RFC 6352 CardDAV August 2011
-
-
- Preconditions:
-
- (CARDDAV:supported-address-data): The attributes "content-type"
- and "version" of the CARDDAV:address-data XML elements (see
- Section 10.4) specify a media type supported by the server for
- address object resources.
-
- Postconditions:
-
- None.
-
-8.7.1. Example: CARDDAV:addressbook-multiget Report
-
- In this example, the client requests the server to return specific
- vCard properties of the address components referenced by specific
- URIs. In addition, the DAV:getetag property is also requested and
- returned as part of the response. Note that, in this example, the
- resource at
- http://addressbook.example.com/home/bernard/addressbook/vcf1.vcf does
- not exist, resulting in an error status response.
-
- >> Request <<
-
- REPORT /home/bernard/addressbook/ HTTP/1.1
- Host: addressbook.example.com
- Depth: 1
- Content-Type: text/xml; charset="utf-8"
- Content-Length: xxxx
-
-
-
-
-
-
-
-
-
-
-
-
-
- /home/bernard/addressbook/vcf102.vcf
- /home/bernard/addressbook/vcf1.vcf
-
-
-
-
-
-
-
-Daboo Standards Track [Page 32]
-
-RFC 6352 CardDAV August 2011
-
-
- >> Response <<
-
- HTTP/1.1 207 Multi-Status
- Date: Sat, 11 Nov 2006 09:32:12 GMT
- Content-Type: text/xml; charset="utf-8"
- Content-Length: xxxx
-
-
-
-
- /home/bernard/addressbook/vcf102.vcf
-
-
- "23ba4d-ff11fb"
- BEGIN:VCARD
- VERSION:3.0
- NICKNAME:me
- UID:34222-232@example.com
- FN:Cyrus Daboo
- EMAIL:daboo@example.com
- END:VCARD
-
-
- HTTP/1.1 200 OK
-
-
-
- /home/bernard/addressbook/vcf1.vcf
- HTTP/1.1 404 Resource not found
-
-
-
-8.7.2. Example: CARDDAV:addressbook-multiget Report
-
- In this example, the client requests the server to return vCard v4.0
- data of the address components referenced by specific URIs. In
- addition, the DAV:getetag property is also requested and returned as
- part of the response. Note that, in this example, the resource at
- http://addressbook.example.com/home/bernard/addressbook/vcf3.vcf
- exists but in a media type format that the server is unable to
- convert, resulting in an error status response.
-
-
-
-
-
-
-
-
-
-Daboo Standards Track [Page 33]
-
-RFC 6352 CardDAV August 2011
-
-
- >> Request <<
-
- REPORT /home/bernard/addressbook/ HTTP/1.1
- Host: addressbook.example.com
- Depth: 1
- Content-Type: text/xml; charset="utf-8"
- Content-Length: xxxx
-
-
-
-
-
-
-
- /home/bernard/addressbook/vcf3.vcf
-
-
- >> Response <<
-
- HTTP/1.1 207 Multi-Status
- Date: Sat, 11 Nov 2006 09:32:12 GMT
- Content-Type: text/xml; charset="utf-8"
- Content-Length: xxxx
-
-
-
-
- /home/bernard/addressbook/vcf3.vcf
- HTTP/1.1 415 Unsupported Media Type
-
- Unable to convert from vCard v3.0
- to vCard v4.0
-
-
-
-9. Client Guidelines
-
-9.1. Restrict the Properties Returned
-
- Clients may not need all the properties in a vCard object when
- presenting information to the user, or looking up specific items for
- their email address, for example. Since some property data can be
- large (e.g., PHOTO or SOUND with in-line content) clients can choose
- to ignore those by only requesting the specific items it knows it
- will use, through use of the CARDDAV:address-data XML element in the
- relevant reports.
-
-
-
-Daboo Standards Track [Page 34]
-
-RFC 6352 CardDAV August 2011
-
-
- However, if a client needs to make a change to a vCard, it can only
- change the entire vCard data via a PUT request. There is no way to
- incrementally make a change to a set of properties within a vCard
- object resource. As a result, the client will have to cache the
- entire set of properties on a resource that is being changed.
-
-9.2. Avoiding Lost Updates
-
- When resources are accessed by multiple clients, the possibility of
- clients overwriting each other's changes exists. To alleviate this,
- clients SHOULD use the If-Match request header on PUT requests with
- the ETag of the previously retrieved resource data to check whether
- the resource was modified since it was previously retrieved. If a
- precondition failure occurs, clients need to reload the resource and
- go through their own merge or conflict resolution process before
- writing back the data (again using the If-Match check).
-
-9.3. Client Configuration
-
- When CardDAV clients need to be configured, the key piece of
- information that they require is the principal-URL of the user whose
- address book information is desired. Servers SHOULD support the
- DAV:current-user-principal-URL property as defined in [RFC5397] to
- give clients a fast way to locate user principals.
-
- Given support for SRV records (Section 11) and DAV:current-user-
- principal-URL [RFC5397], users only need enter a user identifier,
- host name, and password to configure their client. The client would
- take the host name and do an SRV lookup to locate the CardDAV server,
- then execute an authenticated PROPFIND on the root/resource looking
- for the DAV:current-user-principal-URL property. The value returned
- gives the client direct access to the user's principal-URL and from
- there all the related CardDAV properties needed to locate address
- books.
-
-9.4. Finding Other Users' Address Books
-
- For use cases of address book sharing, one might wish to find the
- address book belonging to another user. To find other users' address
- books on the same server, the DAV:principal-property-search REPORT
- [RFC3744] can be used to search principals for matching properties
- and return specified properties for the matching principal resources.
- To search for an address book owned by a user named "Laurie", the
- REPORT request body would look like this:
-
-
-
-
-
-
-
-Daboo Standards Track [Page 35]
-
-RFC 6352 CardDAV August 2011
-
-
-
-
-
-
-
-
- Laurie
-
-
-
-
-
-
-
- The server performs a case-sensitive or caseless search for a
- matching string subset of "Laurie" within the DAV:displayname
- property. Thus, the server might return "Laurie Dusseault", "Laurier
- Desruisseaux", or "Wilfrid Laurier" all as matching DAV:displayname
- values, and the address books for each of these.
-
-10. XML Element Definitions
-
-10.1. CARDDAV:addressbook XML Element
-
- Name: addressbook
-
- Namespace: urn:ietf:params:xml:ns:carddav
-
- Purpose: Specifies the resource type of an address book collection.
-
- Description: See Section 5.2.
-
- Definition:
-
-
-
-10.2. CARDDAV:supported-collation XML Element
-
- Name: supported-collation
-
- Namespace: urn:ietf:params:xml:ns:carddav
-
- Purpose: Identifies a single collation via its collation identifier
- as defined by [RFC4790].
-
- Description: The CARDDAV:supported-collation contains the text of a
- collation identifier as described in Section 8.3.1.
-
-
-
-Daboo Standards Track [Page 36]
-
-RFC 6352 CardDAV August 2011
-
-
- Definition:
-
-
-
-
-10.3. CARDDAV:addressbook-query XML Element
-
- Name: addressbook-query
-
- Namespace: urn:ietf:params:xml:ns:carddav
-
- Purpose: Defines a report for querying address book data
-
- Description: See Section 8.6.
-
- Definition:
-
-
-
-10.4. CARDDAV:address-data XML Element
-
- Name: address-data
-
- Namespace: urn:ietf:params:xml:ns:carddav
-
- Purpose: Specifies one of the following:
-
- 1. The parts of an address object resource that should be
- returned by a given address book REPORT request, and the media
- type and version for the returned data; or
-
- 2. The content of an address object resource in a response to an
- address book REPORT request.
-
- Description: When used in an address book REPORT request, the
- CARDDAV:address-data XML element specifies which parts of address
- object resources need to be returned in the response. If the
- CARDDAV:address-data XML element doesn't contain any CARDDAV:prop
- elements, address object resources will be returned in their
- entirety. Additionally, a media type and version can be specified
- to request that the server return the data in that format if
- possible.
-
- Finally, when used in an address book REPORT response, the
- CARDDAV:address-data XML element specifies the content of an
- address object resource. Given that XML parsers normalize the
-
-
-
-Daboo Standards Track [Page 37]
-
-RFC 6352 CardDAV August 2011
-
-
- two-character sequence CRLF (US-ASCII decimal 13 and US-ASCII
- decimal 10) to a single LF character (US-ASCII decimal 10), the CR
- character (US-ASCII decimal 13) MAY be omitted in address object
- resources specified in the CARDDAV:address-data XML element.
- Furthermore, address object resources specified in the
- CARDDAV:address-data XML element MAY be invalid per their media
- type specification if the CARDDAV:address-data XML element part of
- the address book REPORT request did not specify required vCard
- properties (e.g., UID, etc.) or specified a CARDDAV:prop XML
- element with the "novalue" attribute set to "yes".
-
- Note: The CARDDAV:address-data XML element is specified in requests
- and responses inside the DAV:prop XML element as if it were a
- WebDAV property. However, the CARDDAV:address-data XML element is
- not a WebDAV property and as such it is not returned in PROPFIND
- responses nor used in PROPPATCH requests.
-
- Note: The address data embedded within the CARDDAV:address-data XML
- element MUST follow the standard XML character data encoding
- rules, including use of <, >, & etc., entity encoding or
- the use of a construct. In the latter case, the
- vCard data cannot contain the character sequence "]]>", which is
- the end delimiter for the CDATA section.
-
- Definition:
-
-
-
- when nested in the DAV:prop XML element in an address book
- REPORT request to specify which parts of address object
- resources should be returned in the response;
-
-
-
-
- when nested in the DAV:prop XML element in an address book
- REPORT response to specify the content of a returned
- address object resource.
-
-
-
-
-
- attributes can be used on each variant of the
- CALDAV:address-data XML element.
-
-
-
-
-
-Daboo Standards Track [Page 38]
-
-RFC 6352 CardDAV August 2011
-
-
-10.4.1. CARDDAV:allprop XML Element
-
- Name: allprop
-
- Namespace: urn:ietf:params:xml:ns:carddav
-
- Purpose: Specifies that all vCard properties shall be returned.
-
- Description: This element can be used when the client wants all
- vCard properties of components returned by a report.
-
- Definition:
-
-
-
- Note: The CARDDAV:allprop element defined here has the same name as
- the DAV:allprop element defined in WebDAV. However, the
- CARDDAV:allprop element defined here uses the
- "urn:ietf:params:xml:ns:carddav" namespace, as opposed to the "DAV:"
- namespace used for the DAV:allprop element defined in WebDAV.
-
-10.4.2. CARDDAV:prop XML Element
-
- Name: prop
-
- Namespace: urn:ietf:params:xml:ns:carddav
-
- Purpose: Defines which vCard properties to return in the response.
-
- Description: The "name" attribute specifies the name of the vCard
- property to return (e.g., "NICKNAME"). The "novalue" attribute
- can be used by clients to request that the actual value of the
- property not be returned (if the "novalue" attribute is set to
- "yes"). In that case, the server will return just the vCard
- property name and any vCard parameters and a trailing ":" without
- the subsequent value data.
-
- vCard allows a "group" prefix to appear before a property name in
- the vCard data. When the "name" attribute does not specify a
- group prefix, it MUST match properties in the vCard data without a
- group prefix or with any group prefix. When the "name" attribute
- includes a group prefix, it MUST match properties that have
- exactly the same group prefix and name. For example, a "name" set
- to "TEL" will match "TEL", "X-ABC.TEL", and "X-ABC-1.TEL" vCard
- properties. A "name" set to "X-ABC.TEL" will match an "X-ABC.TEL"
- vCard property only; it will not match "TEL" or "X-ABC-1.TEL".
-
-
-
-
-
-Daboo Standards Track [Page 39]
-
-RFC 6352 CardDAV August 2011
-
-
- Definition:
-
-
-
-
-
-
-
- Note: The CARDDAV:prop element defined here has the same name as the
- DAV:prop element defined in WebDAV. However, the CARDDAV:prop
- element defined here uses the "urn:ietf:params:xml:ns:carddav"
- namespace, as opposed to the "DAV:" namespace used for the DAV:prop
- element defined in WebDAV.
-
-10.5. CARDDAV:filter XML Element
-
- Name: filter
-
- Namespace: urn:ietf:params:xml:ns:carddav
-
- Purpose: Determines which matching objects are returned.
-
- Description: The "filter" element specifies the search filter used
- to match address objects that should be returned by a report. The
- "test" attribute specifies whether any (logical OR) or all
- (logical AND) of the prop-filter tests need to match in order for
- the overall filter to match.
-
- Definition:
-
-
-
-
-
-
-10.5.1. CARDDAV:prop-filter XML Element
-
- Name: prop-filter
-
- Namespace: urn:ietf:params:xml:ns:carddav
-
- Purpose: Limits the search to specific vCard properties.
-
-
-
-
-
-
-Daboo Standards Track [Page 40]
-
-RFC 6352 CardDAV August 2011
-
-
- Description: The CARDDAV:prop-filter XML element specifies search
- criteria on a specific vCard property (e.g., "NICKNAME"). An
- address object is said to match a CARDDAV:prop-filter if:
-
- * A vCard property of the type specified by the "name" attribute
- exists, and the CARDDAV:prop-filter is empty, or it matches any
- specified CARDDAV:text-match or CARDDAV:param-filter
- conditions. The "test" attribute specifies whether any
- (logical OR) or all (logical AND) of the text-filter and param-
- filter tests need to match in order for the overall filter to
- match.
-
- or:
-
- * A vCard property of the type specified by the "name" attribute
- does not exist, and the CARDDAV:is-not-defined element is
- specified.
-
- vCard allows a "group" prefix to appear before a property name in
- the vCard data. When the "name" attribute does not specify a
- group prefix, it MUST match properties in the vCard data without a
- group prefix or with any group prefix. When the "name" attribute
- includes a group prefix, it MUST match properties that have
- exactly the same group prefix and name. For example, a "name" set
- to "TEL" will match "TEL", "X-ABC.TEL", "X-ABC-1.TEL" vCard
- properties. A "name" set to "X-ABC.TEL" will match an "X-ABC.TEL"
- vCard property only, it will not match "TEL" or "X-ABC-1.TEL".
-
- Definition:
-
-
-
-
-
-
-10.5.2. CARDDAV:param-filter XML Element
-
- Name: param-filter
-
- Namespace: urn:ietf:params:xml:ns:carddav
-
- Purpose: Limits the search to specific parameter values.
-
-
-
-
-Daboo Standards Track [Page 41]
-
-RFC 6352 CardDAV August 2011
-
-
- Description: The CARDDAV:param-filter XML element specifies search
- criteria on a specific vCard property parameter (e.g., TYPE) in
- the scope of a given CARDDAV:prop-filter. A vCard property is
- said to match a CARDDAV:param-filter if:
-
- * A parameter of the type specified by the "name" attribute
- exists, and the CARDDAV:param-filter is empty, or it matches
- the CARDDAV:text-match conditions if specified.
-
- or:
-
- * A parameter of the type specified by the "name" attribute does
- not exist, and the CARDDAV:is-not-defined element is specified.
-
- Definition:
-
-
-
-
-
-
-10.5.3. CARDDAV:is-not-defined XML Element
-
- Name: is-not-defined
-
- Namespace: urn:ietf:params:xml:ns:carddav
-
- Purpose: Specifies that a match should occur if the enclosing vCard
- property or parameter does not exist.
-
- Description: The CARDDAV:is-not-defined XML element specifies that a
- match occurs if the enclosing vCard property or parameter value
- specified in an address book REPORT request does not exist in the
- address data being tested.
-
- Definition:
-
-
-
-10.5.4. CARDDAV:text-match XML Element
-
- Name: text-match
-
- Namespace: urn:ietf:params:xml:ns:carddav
-
- Purpose: Specifies a substring match on a vCard property or
- parameter value.
-
-
-
-
-Daboo Standards Track [Page 42]
-
-RFC 6352 CardDAV August 2011
-
-
- Description: The CARDDAV:text-match XML element specifies text used
- for a substring match against the vCard property or parameter
- value specified in an address book REPORT request.
-
- The "collation" attribute is used to select the collation that the
- server MUST use for character string matching. In the absence of
- this attribute, the server MUST use the "i;unicode-casemap"
- collation.
-
- The "negate-condition" attribute is used to indicate that this
- test returns a match if the text matches, when the attribute value
- is set to "no", or return a match if the text does not match, if
- the attribute value is set to "yes". For example, this can be
- used to match components with a CATEGORIES property not set to
- PERSON.
-
- The "match-type" attribute is used to indicate the type of match
- operation to use. Possible choices are:
-
- "equals" - an exact match to the target string
-
- "contains" - a substring match, matching anywhere within the
- target string
-
- "starts-with" - a substring match, matching only at the start
- of the target string
-
- "ends-with" - a substring match, matching only at the end of
- the target string
-
- Definition:
-
-
-
-
-
-
-10.6. CARDDAV:limit XML Element
-
- Name: limit
-
- Namespace: urn:ietf:params:xml:ns:carddav
-
- Purpose: Specifies different types of limits that can be applied to
- the results returned by the server.
-
-
-
-Daboo Standards Track [Page 43]
-
-RFC 6352 CardDAV August 2011
-
-
- Description: The CARDDAV:limit XML element can be used to specify
- different types of limits that the client can request the server
- to apply to the results returned by the server. Currently, only
- the CARDDAV:nresults limit can be used; other types of limit could
- be defined in the future.
-
- Definition:
-
-
-
-10.6.1. CARDDAV:nresults XML Element
-
- Name: nresults
-
- Namespace: urn:ietf:params:xml:ns:carddav
-
- Purpose: Specifies a limit on the number of results returned by the
- server.
-
- Description: The CARDDAV:nresults XML element contains a requested
- maximum number of DAV:response elements to be returned in the
- response body of a query. The server MAY disregard this limit.
- The value of this element is an unsigned integer.
-
- Definition:
-
-
-
-
-10.7. CARDDAV:addressbook-multiget XML Element
-
- Name: addressbook-multiget
-
- Namespace: urn:ietf:params:xml:ns:carddav
-
- Purpose: CardDAV report used to retrieve specific address objects
- via their URIs.
-
- Description: See Section 8.7.
-
- Definition:
-
-
-
-
-
-
-
-Daboo Standards Track [Page 44]
-
-RFC 6352 CardDAV August 2011
-
-
-11. Service Discovery via SRV Records
-
- [RFC2782] defines a DNS-based service discovery protocol that has
- been widely adopted as a means of locating particular services within
- a local area network and beyond, using SRV RRs.
-
- This specification adds two service types for use with SRV records:
-
- carddav: Identifies a CardDAV server that uses HTTP without TLS
- [RFC2818].
-
- carddavs: Identifies a CardDAV server that uses HTTP with TLS
- [RFC2818].
-
- Example: non-TLS service record
-
- _carddav._tcp SRV 0 1 80 addressbook.example.com.
-
- Example: TLS service
-
- _carddavs._tcp SRV 0 1 443 addressbook.example.com.
-
-12. Internationalization Considerations
-
- CardDAV allows internationalized strings to be stored and retrieved
- for the description of address book collections (see Section 6.2.1).
-
- The CARDDAV:addressbook-query REPORT (Section 8.6) includes a text
- searching option controlled by the CARDDAV:text-match element and
- details of character handling are covered in the description of that
- element (see Section 10.5.4).
-
-13. Security Considerations
-
- HTTP protocol transactions are sent in the clear over the network
- unless protection from snooping is negotiated. This can be
- accomplished by use of TLS as defined in [RFC2818]. In particular,
- if HTTP Basic authentication [RFC2617] is available, the server MUST
- allow TLS to be used at the same time, and it SHOULD prevent use of
- Basic authentication when TLS is not in use. Clients SHOULD use TLS
- whenever possible.
-
- With the ACL extension [RFC3744] present, WebDAV allows control over
- who can access (read or write) any resource on the WebDAV server. In
- addition, WebDAV ACL provides for an "inheritance" mechanism, whereby
- resources may inherit access privileges from other resources. Often,
- the "other" resource is a parent collection of the resource itself.
- Servers are able to support address books that are "private"
-
-
diff --git a/lib/servers/mail/imap/README.md b/lib/servers/mail/imap/README.md
deleted file mode 100644
index 67d07895..00000000
--- a/lib/servers/mail/imap/README.md
+++ /dev/null
@@ -1,118 +0,0 @@
-# IMAP Server
-
-A simple IMAP server implementation in V that supports basic mailbox operations.
-
-## Features
-
-- IMAP server implementation with persistent storage via mailbox module
-- Support for multiple mailboxes
-- Basic IMAP commands: LOGIN, SELECT, FETCH, STORE, LOGOUT
-- Message flags support (e.g. \Seen, \Flagged)
-- Concurrent client handling
-
-## Usage
-
-The server can be started with a simple function call:
-
-```v
-import freeflowuniverse.herolib.servers.mail.imap
-import freeflowuniverse.herolib.servers.mail.mailbox
-
-fn main() {
- // Create the mail server
- mut mailserver := mailbox.new_mail_server()
-
- // Create the IMAP server wrapping the mail server
- mut imap_server := imap.new_server(mailserver)
-
- // Start the IMAP server on port 143
- imap_server.start() or { panic(err) }
-}
-```
-
-Save this to `example.v` and run with:
-
-```bash
-v run example.v
-```
-
-The server will start listening on port 143 (default IMAP port).
-
-## Testing with an IMAP Client
-
-You can test the server using any IMAP client. Here's an example using the `curl` command:
-
-```bash
-# Connect and login (any username/password is accepted)
-curl "imap://localhost/" -u "user:pass" --ssl-reqd
-
-# List messages in INBOX
-curl "imap://localhost/INBOX" -u "user:pass" --ssl-reqd
-```
-
-## Implementation Details
-
-The server consists of two main components:
-
-1. **Mailbox Module** (`mailbox/`): Core mail functionality
- - User account management
- - Mailbox operations (create, delete, list)
- - Message storage and retrieval
- - Message flag management
- - Search capabilities
-
-2. **IMAP Server** (`imap/`): IMAP protocol implementation
- - TCP connection handling and session management
- - IMAP command processing
- - Maps IMAP operations to mailbox module functionality
- - Concurrent client support
-
-## Supported Commands
-
-- `CAPABILITY`: List server capabilities
-- `LOGIN`: Authenticate (accepts any credentials)
-- `SELECT`: Select a mailbox
-- `FETCH`: Retrieve message data
-- `STORE`: Update message flags
-- `LOGOUT`: End the session
-
-## Example Session
-
-```
-C: A001 CAPABILITY
-S: * CAPABILITY IMAP4rev1 AUTH=PLAIN
-S: A001 OK CAPABILITY completed
-
-C: A002 LOGIN user pass
-S: A002 OK LOGIN completed
-
-C: A003 SELECT INBOX
-S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
-S: * 2 EXISTS
-S: A003 OK SELECT completed
-
-C: A004 FETCH 1:* BODY[TEXT]
-S: * 1 FETCH (FLAGS (\Seen) BODY[TEXT] "Welcome to the IMAP server!")
-S: * 2 FETCH (FLAGS () BODY[TEXT] "This is an update.")
-S: A004 OK FETCH completed
-
-C: A005 STORE 2 +FLAGS (\Seen)
-S: A005 OK STORE completed
-
-C: A006 CAPABILITY
-S: * CAPABILITY IMAP4rev1 AUTH=PLAIN
-S: A006 OK CAPABILITY completed
-
-C: A007 LOGOUT
-S: * BYE IMAP4rev1 Server logging out
-S: A007 OK LOGOUT completed
-```
-
-## Notes
-
-- The server runs on port 143, which typically requires root privileges. Make sure you have the necessary permissions.
-- This is a basic implementation for demonstration purposes. For production use, consider adding:
- - Proper authentication
- - Full IMAP command support
- - TLS encryption
- - Message parsing and MIME support
diff --git a/lib/servers/mail/imap/cmd_authenticate.v b/lib/servers/mail/imap/cmd_authenticate.v
deleted file mode 100644
index fe25533c..00000000
--- a/lib/servers/mail/imap/cmd_authenticate.v
+++ /dev/null
@@ -1,45 +0,0 @@
-module imap
-
-import net
-import io
-import freeflowuniverse.herolib.ui.console
-
-// handle_authenticate processes the AUTHENTICATE command
-pub fn (mut self Session) handle_authenticate(tag string, parts []string) ! {
- if parts.len < 3 {
- self.conn.write('${tag} BAD AUTHENTICATE requires an authentication mechanism\r\n'.bytes())!
- return
- }
- auth_type := parts[2].to_upper()
- if auth_type == 'PLAIN' {
- // Send continuation request for credentials
- self.conn.write('+ \r\n'.bytes())!
- // Read base64 credentials
- creds := self.reader.read_line() or {
- match err.msg() {
- 'closed' {
- console.print_debug('Client disconnected during authentication')
- return error('client disconnected during auth')
- }
- 'EOF' {
- console.print_debug('Client ended connection during authentication (EOF)')
- return error('connection ended during auth')
- }
- else {
- eprintln('Connection read error during authentication: ${err}')
- return error('connection error during auth: ${err}')
- }
- }
- }
- if creds.len > 0 {
- // For demo purposes, accept any credentials
- // After successful auth, remove STARTTLS and LOGINDISABLED capabilities
- self.capabilities = ['IMAP4rev2', 'AUTH=PLAIN']
- self.conn.write('${tag} OK [CAPABILITY IMAP4rev2 AUTH=PLAIN] Authentication successful\r\n'.bytes())!
- } else {
- self.conn.write('${tag} NO Authentication failed\r\n'.bytes())!
- }
- } else {
- self.conn.write('${tag} NO [ALERT] Unsupported authentication mechanism\r\n'.bytes())!
- }
-}
diff --git a/lib/servers/mail/imap/cmd_capability.v b/lib/servers/mail/imap/cmd_capability.v
deleted file mode 100644
index 10b94340..00000000
--- a/lib/servers/mail/imap/cmd_capability.v
+++ /dev/null
@@ -1,28 +0,0 @@
-module imap
-
-import net
-
-// handle_capability processes the CAPABILITY command
-// See RFC 3501 Section 6.1.1
-pub fn (mut self Session) handle_capability(tag string) ! {
- mut capabilities := []string{}
-
- // IMAP4rev2 is required and must be included
- capabilities << 'IMAP4rev2'
-
- // Required capabilities on cleartext ports
- if !self.tls_active {
- capabilities << 'STARTTLS'
- capabilities << 'LOGINDISABLED'
- }
-
- // Required AUTH capability
- capabilities << 'AUTH=PLAIN'
-
- // Send capabilities in untagged response
- // Note: IMAP4rev2 doesn't need to be first, but must be included
- self.conn.write('* CAPABILITY ${capabilities.join(' ')}\r\n'.bytes())!
-
- // Send tagged OK response
- self.conn.write('${tag} OK CAPABILITY completed\r\n'.bytes())!
-}
diff --git a/lib/servers/mail/imap/cmd_close.v b/lib/servers/mail/imap/cmd_close.v
deleted file mode 100644
index 730088d4..00000000
--- a/lib/servers/mail/imap/cmd_close.v
+++ /dev/null
@@ -1,31 +0,0 @@
-module imap
-
-import net
-
-// handle_close processes the CLOSE command
-// See RFC 3501 Section 6.4.1
-pub fn (mut self Session) handle_close(tag string) ! {
- // If no mailbox is selected, return error
- if self.mailbox == '' {
- self.conn.write('${tag} NO No mailbox selected\r\n'.bytes())!
- return
- }
-
- // Get all messages in the mailbox
- messages := self.server.mailboxserver.message_list(self.username, self.mailbox)!
-
- // Delete messages with \Deleted flag
- for msg in messages {
- if '\\Deleted' in msg.flags {
- self.server.mailboxserver.message_delete(self.username, self.mailbox, msg.uid) or {
- eprintln('Failed to delete message ${msg.uid}: ${err}')
- continue
- }
- }
- }
-
- // Clear selected mailbox
- self.mailbox = ''
-
- self.conn.write('${tag} OK CLOSE completed\r\n'.bytes())!
-}
diff --git a/lib/servers/mail/imap/cmd_fetch.v b/lib/servers/mail/imap/cmd_fetch.v
deleted file mode 100644
index 0272a4a8..00000000
--- a/lib/servers/mail/imap/cmd_fetch.v
+++ /dev/null
@@ -1,183 +0,0 @@
-module imap
-
-import net
-import strconv
-
-// handle_fetch processes the FETCH command
-// See RFC 3501 Section 6.4.5
-pub fn (mut self Session) handle_fetch(tag string, parts []string) ! {
- // Check if user is logged in
- if self.username == '' {
- self.conn.write('${tag} NO Must be logged in first\r\n'.bytes())!
- return error('Not logged in')
- }
-
- if parts.len < 4 {
- self.conn.write('${tag} BAD FETCH requires a message sequence and data item\r\n'.bytes())!
- return
- }
-
- sequence := parts[2]
- // Join remaining parts to handle parenthesized items
- data_items := parts[3..].join(' ').trim('()')
-
- // Parse data items, handling quoted strings and parentheses
- mut items_to_fetch := []string{}
- mut current_item := ''
- mut in_brackets := false
-
- for c in data_items {
- match c {
- `[` {
- in_brackets = true
- current_item += c.ascii_str()
- }
- `]` {
- in_brackets = false
- current_item += c.ascii_str()
- if current_item != '' {
- items_to_fetch << current_item.trim_space()
- current_item = ''
- }
- }
- ` ` {
- if in_brackets {
- current_item += c.ascii_str()
- } else if current_item != '' {
- items_to_fetch << current_item.trim_space()
- current_item = ''
- }
- }
- else {
- current_item += c.ascii_str()
- }
- }
- }
- if current_item != '' {
- items_to_fetch << current_item.trim_space()
- }
-
- // Convert to uppercase for matching
- items_to_fetch = items_to_fetch.map(it.to_upper())
-
- // Get all messages in mailbox
- messages := self.server.mailboxserver.message_list(self.username, self.mailbox)!
- total_messages := messages.len
-
- // Parse sequence range
- mut start_idx := 0
- mut end_idx := 0
-
- if sequence == '1:*' {
- start_idx = 0
- end_idx = total_messages - 1
- } else if sequence.contains(':') {
- range_parts := sequence.split(':')
- if range_parts.len != 2 {
- self.conn.write('${tag} BAD Invalid sequence range\r\n'.bytes())!
- return
- }
- start_idx = strconv.atoi(range_parts[0]) or {
- self.conn.write('${tag} BAD Invalid sequence range start\r\n'.bytes())!
- return
- } - 1
- if range_parts[1] == '*' {
- end_idx = total_messages - 1
- } else {
- end_idx = strconv.atoi(range_parts[1]) or {
- self.conn.write('${tag} BAD Invalid sequence range end\r\n'.bytes())!
- return
- } - 1
- }
- } else {
- // Single message number
- start_idx = strconv.atoi(sequence) or {
- self.conn.write('${tag} BAD Invalid message number\r\n'.bytes())!
- return
- } - 1
- end_idx = start_idx
- }
-
- if start_idx < 0 || end_idx >= total_messages || start_idx > end_idx {
- self.conn.write('${tag} NO Invalid message range\r\n'.bytes())!
- return
- }
-
- // Process messages in range
- for i := start_idx; i <= end_idx; i++ {
- msg := messages[i]
- mut response := []string{}
-
- // Always include UID in FETCH responses
- response << 'UID ${msg.uid}'
-
- for item in items_to_fetch {
- match item {
- 'FLAGS' {
- flags_str := if msg.flags.len > 0 {
- msg.flags.join(' ')
- } else {
- ''
- }
- response << 'FLAGS (${flags_str})'
- }
- 'INTERNALDATE' {
- response << 'INTERNALDATE "${msg.internal_date.str()}"'
- }
- 'RFC822.SIZE' {
- response << 'RFC822.SIZE ${msg.body.len}'
- }
- 'BODY[TEXT]' {
- // Mark message as seen unless using BODY.PEEK
- if !item.contains('.PEEK') {
- if '\\Seen' !in msg.flags {
- mut updated_msg := msg
- updated_msg.flags << '\\Seen'
- self.server.mailboxserver.message_set(self.username, self.mailbox,
- msg.uid, updated_msg) or {
- eprintln('Failed to update \\Seen flag: ${err}')
- }
- }
- }
- response << 'BODY[TEXT] {${msg.body.len}}\r\n${msg.body}'
- }
- 'BODY[]', 'BODY.PEEK[]' {
- // Mark message as seen unless using BODY.PEEK
- if !item.contains('.PEEK') {
- if '\\Seen' !in msg.flags {
- mut updated_msg := msg
- updated_msg.flags << '\\Seen'
- self.server.mailboxserver.message_set(self.username, self.mailbox,
- msg.uid, updated_msg) or {
- eprintln('Failed to update \\Seen flag: ${err}')
- }
- }
- }
- // For BODY[], return the full message including headers
- mut full_msg := 'From: <>\r\n'
- full_msg += 'Subject: ${msg.subject}\r\n'
- full_msg += 'Date: ${msg.internal_date.str()}\r\n'
- full_msg += '\r\n' // Empty line between headers and body
- full_msg += msg.body
- response << 'BODY[] {${full_msg.len}}\r\n${full_msg}'
- }
- 'BODY[HEADER]', 'BODY.PEEK[HEADER]' {
- // Return just the headers
- mut headers := 'From: <>\r\n'
- headers += 'Subject: ${msg.subject}\r\n'
- headers += 'Date: ${msg.internal_date.str()}\r\n'
- headers += '\r\n' // Empty line after headers
- response << 'BODY[HEADER] {${headers.len}}\r\n${headers}'
- }
- 'ENVELOPE' {
- // Basic envelope with just subject for now
- response << 'ENVELOPE (NIL "${msg.subject}" NIL NIL NIL NIL NIL NIL NIL NIL)'
- }
- else {}
- }
- }
-
- self.conn.write('* ${i + 1} FETCH (${response.join(' ')})\r\n'.bytes())!
- }
- self.conn.write('${tag} OK FETCH completed\r\n'.bytes())!
-}
diff --git a/lib/servers/mail/imap/cmd_list.v b/lib/servers/mail/imap/cmd_list.v
deleted file mode 100644
index 8db455f0..00000000
--- a/lib/servers/mail/imap/cmd_list.v
+++ /dev/null
@@ -1,122 +0,0 @@
-module imap
-
-import net
-
-// handle_list processes the LIST command
-// See RFC 3501 Section 6.3.9
-pub fn (mut self Session) handle_list(tag string, parts []string) ! {
- // Check if user is logged in
- if self.username == '' {
- self.conn.write('${tag} NO Must be logged in first\r\n'.bytes())!
- return error('Not logged in')
- }
-
- if parts.len < 4 {
- self.conn.write('${tag} BAD LIST requires reference name and mailbox name\r\n'.bytes())!
- return
- }
-
- reference := parts[2].trim('"')
- pattern := parts[3].trim('"')
-
- // For now, we only support empty reference and simple patterns
- if reference != '' && reference != 'INBOX' {
- // Just return OK with no results for unsupported references
- self.conn.write('${tag} OK LIST completed\r\n'.bytes())!
- return
- }
-
- // Handle special case of empty mailbox name
- if pattern == '' {
- // Return hierarchy delimiter and root name
- self.conn.write('* LIST (\\Noselect) "/" ""\r\n'.bytes())!
- self.conn.write('${tag} OK LIST completed\r\n'.bytes())!
- return
- }
-
- // Get list of mailboxes for the user using mailbox module
- mailbox_names := self.server.mailboxserver.mailbox_list(self.username) or {
- self.conn.write('${tag} NO Failed to list mailboxes\r\n'.bytes())!
- return error('Failed to list mailboxes: ${err}')
- }
-
- // Handle % wildcard (single level)
- if pattern == '%' {
- // List top-level mailboxes
- for name in mailbox_names {
- if !name.contains('/') { // Only top level
- // Since we don't have direct access to read-only status, use basic attributes
- mut attrs := []string{}
-
- // Add child status attributes
- mut has_children := false
- for other_name in mailbox_names {
- if other_name.starts_with(name + '/') {
- has_children = true
- break
- }
- }
- if has_children {
- attrs << '\\HasChildren'
- } else {
- attrs << '\\HasNoChildren'
- }
- attr_str := if attrs.len > 0 { '(${attrs.join(' ')})' } else { '()' }
- self.conn.write('* LIST ${attr_str} "/" "${name}"\r\n'.bytes())!
- }
- }
- self.conn.write('${tag} OK LIST completed\r\n'.bytes())!
- return
- }
-
- // Handle * wildcard (multiple levels)
- if pattern == '*' {
- // List all mailboxes
- for name in mailbox_names {
- // Since we don't have direct access to read-only status, use basic attributes
- mut attrs := []string{}
-
- // Add child status attributes
- mut has_children := false
- for other_name in mailbox_names {
- if other_name.starts_with(name + '/') {
- has_children = true
- break
- }
- }
- if has_children {
- attrs << '\\HasChildren'
- } else {
- attrs << '\\HasNoChildren'
- }
- attr_str := if attrs.len > 0 { '(${attrs.join(' ')})' } else { '()' }
- self.conn.write('* LIST ${attr_str} "/" "${name}"\r\n'.bytes())!
- }
- self.conn.write('${tag} OK LIST completed\r\n'.bytes())!
- return
- }
-
- // Handle exact mailbox name
- if pattern in mailbox_names {
- // Since we don't have direct access to read-only status, use basic attributes
- mut attrs := []string{}
-
- // Add child status attributes
- mut has_children := false
- for other_name in mailbox_names {
- if other_name.starts_with(pattern + '/') {
- has_children = true
- break
- }
- }
- if has_children {
- attrs << '\\HasChildren'
- } else {
- attrs << '\\HasNoChildren'
- }
- attr_str := if attrs.len > 0 { '(${attrs.join(' ')})' } else { '()' }
- self.conn.write('* LIST ${attr_str} "/" "${pattern}"\r\n'.bytes())!
- }
-
- self.conn.write('${tag} OK LIST completed\r\n'.bytes())!
-}
diff --git a/lib/servers/mail/imap/cmd_login.v b/lib/servers/mail/imap/cmd_login.v
deleted file mode 100644
index 02eacc84..00000000
--- a/lib/servers/mail/imap/cmd_login.v
+++ /dev/null
@@ -1,45 +0,0 @@
-module imap
-
-import net
-
-// handle_login processes the LOGIN command
-// See RFC 3501 Section 6.2.3
-pub fn (mut self Session) handle_login(tag string, parts []string) ! {
- // Check if LOGINDISABLED is advertised
- if self.capabilities.contains('LOGINDISABLED') {
- self.conn.write('${tag} NO [PRIVACYREQUIRED] LOGIN disabled\r\n'.bytes())!
- return
- }
-
- if parts.len < 4 {
- self.conn.write('${tag} BAD LOGIN requires username and password\r\n'.bytes())!
- return
- }
-
- username := parts[2]
- password := parts[3]
-
- // For demo purposes, accept any username and look it up in the mailbox server
- // In a real implementation, we would validate the password here
-
- // Try to find existing account by email
- email := '${username}@example.com'
- existing_username := self.server.mailboxserver.account_find_by_email(email) or {
- // Create a new account if not found
- self.server.mailboxserver.account_create(username, username, [
- '${username}@example.com',
- ]) or {
- self.conn.write('${tag} NO [AUTHENTICATIONFAILED] Failed to create account\r\n'.bytes())!
- return
- }
- username // Return the new username
- }
-
- self.username = existing_username
-
- // Update capabilities - remove LOGINDISABLED and STARTTLS after login
- self.capabilities = self.capabilities.filter(it != 'LOGINDISABLED' && it != 'STARTTLS')
-
- // Send OK response with updated capabilities
- self.conn.write('${tag} OK [CAPABILITY ${self.capabilities.join(' ')}] LOGIN completed\r\n'.bytes())!
-}
diff --git a/lib/servers/mail/imap/cmd_logout.v b/lib/servers/mail/imap/cmd_logout.v
deleted file mode 100644
index 43093389..00000000
--- a/lib/servers/mail/imap/cmd_logout.v
+++ /dev/null
@@ -1,9 +0,0 @@
-module imap
-
-import net
-
-// handle_logout processes the LOGOUT command
-pub fn (mut self Session) handle_logout(tag string) ! {
- self.conn.write('* BYE IMAP4rev2 Server logging out\r\n'.bytes())!
- self.conn.write('${tag} OK LOGOUT completed\r\n'.bytes())!
-}
diff --git a/lib/servers/mail/imap/cmd_select.v b/lib/servers/mail/imap/cmd_select.v
deleted file mode 100644
index 9866114f..00000000
--- a/lib/servers/mail/imap/cmd_select.v
+++ /dev/null
@@ -1,57 +0,0 @@
-module imap
-
-import net
-
-// handle_select processes the SELECT command
-// See RFC 3501 Section 6.3.2
-pub fn (mut self Session) handle_select(tag string, parts []string) ! {
- if parts.len < 3 {
- self.conn.write('${tag} BAD SELECT requires a mailbox name\r\n'.bytes())!
- return error('SELECT requires a mailbox name')
- }
-
- // Check if user is logged in
- if self.username == '' {
- self.conn.write('${tag} NO Must be logged in first\r\n'.bytes())!
- return error('Not logged in')
- }
-
- // If there's a currently selected mailbox, send CLOSED response
- if self.mailbox != '' {
- self.conn.write('* OK [CLOSED] Previous mailbox is now closed\r\n'.bytes())!
- }
-
- // Remove any surrounding quotes from mailbox name
- mailbox_name := parts[2].trim('"')
-
- // Check if mailbox exists by trying to list messages
- messages := self.server.mailboxserver.message_list(self.username, mailbox_name) or {
- self.conn.write('${tag} NO Mailbox does not exist\r\n'.bytes())!
- return error('Mailbox does not exist')
- }
-
- messages_count := messages.len
-
- // Required untagged responses per spec:
- // 1. FLAGS - list of flags that can be set on messages
- self.conn.write('* FLAGS (\\Answered \\Flagged \\Deleted \\Seen \\Draft)\r\n'.bytes())!
-
- // 2. EXISTS - number of messages
- self.conn.write('* ${messages_count} EXISTS\r\n'.bytes())!
-
- // Required OK untagged responses:
- // 1. PERMANENTFLAGS
- self.conn.write('* OK [PERMANENTFLAGS (\\Answered \\Flagged \\Deleted \\Seen \\Draft \\*)] Flags permitted\r\n'.bytes())!
-
- // 2. UIDNEXT - Use a high number since we don't have direct access to next_uid
- self.conn.write('* OK [UIDNEXT 4294967295] Predicted next UID\r\n'.bytes())!
-
- // 3. UIDVALIDITY - Use a constant since we don't have direct access to uid_validity
- self.conn.write('* OK [UIDVALIDITY 1] UIDs valid\r\n'.bytes())!
-
- // Update session's selected mailbox
- self.mailbox = mailbox_name
-
- // Always use READ-WRITE mode since we don't have read-only information
- self.conn.write('${tag} OK [READ-WRITE] SELECT completed\r\n'.bytes())!
-}
diff --git a/lib/servers/mail/imap/cmd_store.v b/lib/servers/mail/imap/cmd_store.v
deleted file mode 100644
index 0a1d9a7d..00000000
--- a/lib/servers/mail/imap/cmd_store.v
+++ /dev/null
@@ -1,98 +0,0 @@
-module imap
-
-import net
-import strconv
-
-// handle_store processes the STORE command
-// See RFC 3501 Section 6.4.6
-pub fn (mut self Session) handle_store(tag string, parts []string) ! {
- // Check if user is logged in
- if self.username == '' {
- self.conn.write('${tag} NO Must be logged in first\r\n'.bytes())!
- return error('Not logged in')
- }
-
- // Expecting format like: A003 STORE sequence-set operation flags
- if parts.len < 5 {
- self.conn.write('${tag} BAD STORE requires a sequence-set, an operation, and flags\r\n'.bytes())!
- return
- }
-
- // Get all messages to find the target message
- messages := self.server.mailboxserver.message_list(self.username, self.mailbox)!
-
- // Parse sequence set (currently only supporting single message numbers)
- sequence := parts[2]
- index := strconv.atoi(sequence) or {
- self.conn.write('${tag} BAD Invalid sequence-set\r\n'.bytes())!
- return
- } - 1
-
- if index < 0 || index >= messages.len {
- self.conn.write('${tag} NO No such message\r\n'.bytes())!
- return
- }
-
- // Parse operation (FLAGS, +FLAGS, -FLAGS, with optional .SILENT)
- op := parts[3]
- silent := op.ends_with('.SILENT')
- base_op := if silent { op[..op.len - 7] } else { op }
-
- if base_op !in ['FLAGS', '+FLAGS', '-FLAGS'] {
- self.conn.write('${tag} BAD Unknown STORE operation\r\n'.bytes())!
- return
- }
-
- // Parse flags
- flags_str := parts[4]
- flags_clean := flags_str.trim('()')
- flags_arr := flags_clean.split(' ').filter(it != '')
-
- // Validate flags
- valid_flags := ['\\Answered', '\\Flagged', '\\Deleted', '\\Seen', '\\Draft']
- for flag in flags_arr {
- if !flag.starts_with('\\') || flag !in valid_flags {
- self.conn.write('${tag} BAD Invalid flag\r\n'.bytes())!
- return
- }
- }
-
- mut msg := messages[index]
- old_flags := msg.flags.clone() // Save for comparison
-
- // Apply flag changes
- match base_op {
- '+FLAGS' {
- // Add each flag if it isn't already present
- for flag in flags_arr {
- if flag !in msg.flags {
- msg.flags << flag
- }
- }
- }
- '-FLAGS' {
- // Remove specified flags
- for flag in flags_arr {
- msg.flags = msg.flags.filter(it != flag)
- }
- }
- 'FLAGS' {
- // Replace current flags
- msg.flags = flags_arr
- }
- else {}
- }
-
- // Save the updated message using mailbox module's message_set
- self.server.mailboxserver.message_set(self.username, self.mailbox, msg.uid, msg) or {
- self.conn.write('${tag} NO Failed to update message flags\r\n'.bytes())!
- return error('Failed to update message flags: ${err}')
- }
-
- // Send untagged FETCH response if flags changed and not silent
- if !silent && msg.flags != old_flags {
- self.conn.write('* ${index + 1} FETCH (FLAGS (${msg.flags.join(' ')}))\r\n'.bytes())!
- }
-
- self.conn.write('${tag} OK STORE completed\r\n'.bytes())!
-}
diff --git a/lib/servers/mail/imap/cmd_uid.v b/lib/servers/mail/imap/cmd_uid.v
deleted file mode 100644
index b01dd536..00000000
--- a/lib/servers/mail/imap/cmd_uid.v
+++ /dev/null
@@ -1,53 +0,0 @@
-module imap
-
-import net
-
-// handle_uid processes the UID command
-// See RFC 3501 Section 6.4.9
-pub fn (mut self Session) handle_uid(tag string, parts []string) ! {
- if parts.len < 3 {
- self.conn.write('${tag} BAD UID requires a command\r\n'.bytes())!
- return
- }
-
- subcmd := parts[2].to_upper()
- match subcmd {
- 'FETCH' {
- // Remove 'UID' from parts and pass to handle_fetch
- // The handle_fetch implementation already includes UIDs in responses
- mut fetch_parts := parts.clone()
- fetch_parts.delete(1) // Remove 'UID'
- self.handle_fetch(tag, fetch_parts)!
- }
- 'SEARCH' {
- // Remove 'UID' from parts and pass to handle_search
- mut search_parts := parts.clone()
- search_parts.delete(1) // Remove 'UID'
- // TODO: Implement handle_search
- self.conn.write('${tag} NO SEARCH not implemented\r\n'.bytes())!
- }
- 'STORE' {
- // Remove 'UID' from parts and pass to handle_store
- mut store_parts := parts.clone()
- store_parts.delete(1) // Remove 'UID'
- self.handle_store(tag, store_parts)!
- }
- 'COPY' {
- // Remove 'UID' from parts and pass to handle_copy
- mut copy_parts := parts.clone()
- copy_parts.delete(1) // Remove 'UID'
- // TODO: Implement handle_copy
- self.conn.write('${tag} NO COPY not implemented\r\n'.bytes())!
- }
- 'EXPUNGE' {
- // Remove 'UID' from parts and pass to handle_expunge
- mut expunge_parts := parts.clone()
- expunge_parts.delete(1) // Remove 'UID'
- // TODO: Implement handle_expunge
- self.conn.write('${tag} NO EXPUNGE not implemented\r\n'.bytes())!
- }
- else {
- self.conn.write('${tag} BAD Unknown UID command\r\n'.bytes())!
- }
- }
-}
diff --git a/lib/servers/mail/imap/factory.v b/lib/servers/mail/imap/factory.v
deleted file mode 100644
index e38b2099..00000000
--- a/lib/servers/mail/imap/factory.v
+++ /dev/null
@@ -1,12 +0,0 @@
-module imap
-
-import time
-import freeflowuniverse.herolib.servers.mail.mailbox
-
-pub fn new(mailboxserver &mailbox.MailServer) !IMAPServer {
- mut server := IMAPServer{
- mailboxserver: mailboxserver
- }
-
- return server
-}
diff --git a/lib/servers/mail/imap/model.v b/lib/servers/mail/imap/model.v
deleted file mode 100644
index 7283b43c..00000000
--- a/lib/servers/mail/imap/model.v
+++ /dev/null
@@ -1,41 +0,0 @@
-module imap
-
-import net
-import io
-import freeflowuniverse.herolib.servers.mail.mailbox
-
-// IMAPServer wraps the mailbox server to provide IMAP functionality
-@[heap]
-pub struct IMAPServer {
-pub mut:
- mailboxserver &mailbox.MailServer
-}
-
-// Session represents an active IMAP client connection
-pub struct Session {
-pub mut:
- server &IMAPServer
- username string // Currently logged in user
- mailbox string // Currently selected mailbox name
- conn net.TcpConn
- reader &io.BufferedReader
- tls_active bool // Whether TLS is active on the connection
- capabilities []string // Current capabilities for this session
-}
-
-// mailbox_new creates a new mailbox for the current user
-pub fn (mut self Session) mailbox_new(name string) ! {
- if self.username == '' {
- return error('No user logged in')
- }
- self.server.mailboxserver.mailbox_create(self.username, name)!
-}
-
-// mailbox_exists checks if the currently selected mailbox exists
-pub fn (mut self Session) mailbox_exists() bool {
- if self.username == '' || self.mailbox == '' {
- return false
- }
- mailboxes := self.server.mailboxserver.mailbox_list(self.username) or { return false }
- return self.mailbox in mailboxes
-}
diff --git a/lib/servers/mail/imap/server.v b/lib/servers/mail/imap/server.v
deleted file mode 100644
index 4ba281d6..00000000
--- a/lib/servers/mail/imap/server.v
+++ /dev/null
@@ -1,137 +0,0 @@
-module imap
-
-import net
-import strings
-import freeflowuniverse.herolib.ui.console
-import time
-import io
-
-// Run starts the server on port 143 and accepts client connections.
-pub fn (mut server IMAPServer) start() ! {
- spawn daemon(mut server)
-}
-
-fn daemon(mut server IMAPServer) ! {
- addr := '0.0.0.0:143'
- mut listener := net.listen_tcp(.ip, addr, dualstack: true) or {
- return error('Failed to listen on ${addr}: ${err}')
- }
- println('IMAP Server listening on ${addr}')
-
- // Set TCP options for better reliability
- // listener.set_option_bool(.reuse_addr, true)
-
- for {
- mut conn := listener.accept() or {
- eprintln('Failed to accept connection: ${err}')
- continue
- }
-
- // Set connection options
-
- // conn.set_option_int(.tcp_keepalive, 60)!
- conn.set_read_timeout(30 * time.second)
- conn.set_write_timeout(30 * time.second)
-
- // Handle each connection concurrently
- spawn handle_connection(mut conn, mut server)
- }
-}
-
-// handle_connection processes commands from a connected client.
-fn handle_connection(mut conn net.TcpConn, mut server IMAPServer) ! {
- // Send greeting per IMAP protocol.
- defer {
- conn.close() or { panic(err) }
- }
- conn.write('* OK [CAPABILITY IMAP4rev2 STARTTLS LOGINDISABLED AUTH=PLAIN] IMAP server ready\r\n'.bytes())!
- // Initially no mailbox is selected.
- mut selected_mailbox_name := ''
- mut res := false
- client_addr := conn.peer_addr()!
- console.print_debug('> new client: ${client_addr}')
- mut reader := io.new_buffered_reader(reader: conn)
- defer {
- unsafe {
- reader.free()
- }
- }
-
- mut session := Session{
- server: &server
- mailbox: ''
- conn: conn
- reader: reader
- tls_active: false
- capabilities: ['IMAP4rev2', 'STARTTLS', 'LOGINDISABLED', 'AUTH=PLAIN']
- }
-
- for {
- // Read a line (command) from the client.
- line := reader.read_line() or {
- match err.msg() {
- 'closed' {
- console.print_debug('Client disconnected normally')
- return error('client disconnected')
- }
- 'EOF' {
- console.print_debug('Client connection ended (EOF)')
- return error('connection ended')
- }
- else {
- eprintln('Connection read error: ${err}')
- return error('connection error: ${err}')
- }
- }
- }
- console.print_debug(line)
- trimmed := line.trim_space()
- if trimmed.len == 0 {
- continue
- }
- // Commands come with a tag followed by the command and parameters.
- parts := trimmed.split(' ')
- if parts.len < 2 {
- conn.write('${parts[0]} BAD Invalid command\r\n'.bytes())!
- continue
- }
- tag := parts[0]
- cmd := parts[1].to_upper()
- match cmd {
- 'LOGIN' {
- session.handle_login(tag, parts)!
- }
- 'AUTHENTICATE' {
- session.handle_authenticate(tag, parts)!
- }
- 'SELECT' {
- session.handle_select(tag, parts)!
- }
- 'FETCH' {
- session.handle_fetch(tag, parts)!
- }
- 'STORE' {
- session.handle_store(tag, parts)!
- }
- 'CAPABILITY' {
- session.handle_capability(tag)!
- }
- 'LIST' {
- session.handle_list(tag, parts)!
- }
- 'UID' {
- session.handle_uid(tag, parts)!
- }
- 'CLOSE' {
- session.handle_close(tag)!
- }
- 'LOGOUT' {
- session.handle_logout(tag)!
- return
- }
- else {
- conn.write('${tag} BAD Unknown command\r\n'.bytes())!
- }
- }
- }
-}
diff --git a/lib/servers/mail/imap/specs/imap_3501.md b/lib/servers/mail/imap/specs/imap_3501.md
deleted file mode 100644
index 2ee2e7dc..00000000
--- a/lib/servers/mail/imap/specs/imap_3501.md
+++ /dev/null
@@ -1,6875 +0,0 @@
- Internet Message Access Protocol (IMAP) - Version 4rev2
-
-Abstract
-
- The Internet Message Access Protocol Version 4rev2 (IMAP4rev2) allows
- a client to access and manipulate electronic mail messages on a
- server. IMAP4rev2 permits manipulation of mailboxes (remote message
- folders) in a way that is functionally equivalent to local folders.
- IMAP4rev2 also provides the capability for an offline client to
- resynchronize with the server.
-
- IMAP4rev2 includes operations for creating, deleting, and renaming
- mailboxes; checking for new messages; removing messages permanently;
- setting and clearing flags; parsing per RFCs 5322, 2045, and 2231;
- searching; and selective fetching of message attributes, texts, and
- portions thereof. Messages in IMAP4rev2 are accessed by the use of
- numbers. These numbers are either message sequence numbers or unique
- identifiers.
-
- IMAP4rev2 does not specify a means of posting mail; this function is
- handled by a mail submission protocol such as the one specified in
- RFC 6409.
-
-1. Protocol Overview
-
-2.1. Link Level
-
- The IMAP4rev2 protocol assumes a reliable data stream such as that
- provided by TCP. When TCP is used, an IMAP4rev2 server listens on
- port 143 (cleartext port) or port 993 (Implicit TLS port).
-
-2.2. Commands and Responses
-
- An IMAP4rev2 connection consists of the establishment of a client/
- server network connection, an initial greeting from the server, and
- client/server interactions. These client/server interactions consist
- of a client command, server data, and a server completion result
- response.
-
- All interactions transmitted by client and server are in the form of
- lines, that is, strings that end with a CRLF. The protocol receiver
- of an IMAP4rev2 client or server is reading either a line or a
- sequence of octets with a known count followed by a line.
-
-2.2.1. Client Protocol Sender and Server Protocol Receiver
-
- The client command begins an operation. Each client command is
- prefixed with an identifier (typically a short alphanumeric string,
- e.g., A0001, A0002, etc.) called a "tag". A different tag is
- generated by the client for each command. More formally: the client
- SHOULD generate a unique tag for every command, but a server MUST
- accept tag reuse.
-
- Clients MUST follow the syntax outlined in this specification
- strictly. It is a syntax error to send a command with missing or
- extraneous spaces or arguments.
-
- There are two cases in which a line from the client does not
- represent a complete command. In one case, a command argument is
- quoted with an octet count (see the description of literal in
- Section 4.3); in the other case, the command arguments require server
- feedback (see the AUTHENTICATE command in Section 6.2.2). In either
- case, the server sends a command continuation request response if it
- is ready for the octets (if appropriate) and the remainder of the
- command. This response is prefixed with the token "+".
-
- Note: If, instead, the server detected an error in the command, it
- sends a BAD completion response with a tag matching the command
- (as described below) to reject the command and prevent the client
- from sending any more of the command.
-
- It is also possible for the server to send a completion response
- for some other command (if multiple commands are in progress) or
- untagged data. In either case, the command continuation request
- is still pending; the client takes the appropriate action for the
- response and reads another response from the server. In all
- cases, the client MUST send a complete command (including
- receiving all command continuation request responses and sending
- command continuations for the command) before initiating a new
- command.
-
- The protocol receiver of an IMAP4rev2 server reads a command line
- from the client, parses the command and its arguments, and transmits
- server data and a server command completion result response.
-
-2.2.2. Server Protocol Sender and Client Protocol Receiver
-
- Data transmitted by the server to the client and status responses
- that do not indicate command completion are prefixed with the token
- "*" and are called untagged responses.
-
- Server data MAY be sent as a result of a client command or MAY be
- sent unilaterally by the server. There is no syntactic difference
- between server data that resulted from a specific command and server
- data that were sent unilaterally.
-
- The server completion result response indicates the success or
- failure of the operation. It is tagged with the same tag as the
- client command that began the operation. Thus, if more than one
- command is in progress, the tag in a server completion response
- identifies the command to which the response applies. There are
- three possible server completion responses: OK (indicating success),
- NO (indicating failure), or BAD (indicating a protocol error such as
- unrecognized command or command syntax error).
-
- Servers SHOULD strictly enforce the syntax outlined in this
- specification. Any client command with a protocol syntax error,
- including (but not limited to) missing or extraneous spaces or
- arguments, SHOULD be rejected and the client given a BAD server
- completion response.
-
- The protocol receiver of an IMAP4rev2 client reads a response line
- from the server. It then takes action on the response based upon the
- first token of the response, which can be a tag, a "*", or a "+".
-
- A client MUST be prepared to accept any server response at all times.
- This includes server data that was not requested. Server data SHOULD
- be remembered (cached), so that the client can reference its
- remembered copy rather than sending a command to the server to
- request the data. In the case of certain server data, the data MUST
- be remembered, as specified elsewhere in this document.
-
- This topic is discussed in greater detail in "Server Responses" (see
- Section 7).
-
-2.3. Message Attributes
-
- In addition to message text, each message has several attributes
- associated with it. These attributes can be retrieved individually
- or in conjunction with other attributes or message texts.
-
-2.3.1. Message Numbers
-
- Messages in IMAP4rev2 are accessed by one of two numbers: the Unique
- Identifier (UID) or the message sequence number.
-
-2.3.1.1. Unique Identifier (UID) Message Attribute
-
- A UID is an unsigned non-zero 32-bit value assigned to each message,
- which when used with the unique identifier validity value (see below)
- forms a 64-bit value that MUST NOT refer to any other message in the
- mailbox or any subsequent mailbox with the same name forever. Unique
- identifiers are assigned in a strictly ascending fashion in the
- mailbox; as each message is added to the mailbox, it is assigned a
- higher UID than those of all message(s) that are already in the
- mailbox. Unlike message sequence numbers, unique identifiers are not
- necessarily contiguous.
-
- The unique identifier of a message MUST NOT change during the session
- and SHOULD NOT change between sessions. Any change of unique
- identifiers between sessions MUST be detectable using the UIDVALIDITY
- mechanism discussed below. Persistent unique identifiers are
- required for a client to resynchronize its state from a previous
- session with the server (e.g., disconnected or offline access clients
- [IMAP-MODEL]); this is discussed further in [IMAP-DISC].
-
- Associated with every mailbox are two 32-bit unsigned non-zero values
- that aid in unique identifier handling: the next unique identifier
- value (UIDNEXT) and the unique identifier validity value
- (UIDVALIDITY).
-
- The next unique identifier value is the predicted value that will be
- assigned to a new message in the mailbox. Unless the unique
- identifier validity also changes (see below), the next unique
- identifier value MUST have the following two characteristics. First,
- the next unique identifier value MUST NOT change unless new messages
- are added to the mailbox; and second, the next unique identifier
- value MUST change whenever new messages are added to the mailbox,
- even if those new messages are subsequently expunged.
-
- | Note: The next unique identifier value is intended to provide a
- | means for a client to determine whether any messages have been
- | delivered to the mailbox since the previous time it checked
- | this value. It is not intended to provide any guarantee that
- | any message will have this unique identifier. A client can
- | only assume, at the time that it obtains the next unique
- | identifier value, that messages arriving after that time will
- | have a UID greater than or equal to that value.
-
- The unique identifier validity value is sent in a UIDVALIDITY
- response code in an OK untagged response at mailbox selection time.
- If unique identifiers from an earlier session fail to persist in this
- session, the unique identifier validity value MUST be greater than
- the one used in the earlier session. A good UIDVALIDITY value to use
- is a 32-bit representation of the current date/time when the value is
- assigned: this ensures that the value is unique and always increases.
- Another possible alternative is a global counter that gets
- incremented every time a mailbox is created.
-
- Note: Ideally, unique identifiers SHOULD persist at all times.
- Although this specification recognizes that failure to persist can
- be unavoidable in certain server environments, it strongly
- encourages message store implementation techniques that avoid this
- problem. For example:
-
- 1. Unique identifiers MUST be strictly ascending in the mailbox at
- all times. If the physical message store is reordered by a non-
- IMAP agent, the unique identifiers in the mailbox MUST be
- regenerated, since the former unique identifiers are no longer
- strictly ascending as a result of the reordering.
-
- 2. If the message store has no mechanism to store unique
- identifiers, it must regenerate unique identifiers at each
- session, and each session must have a unique UIDVALIDITY value.
- Note that this situation can be very disruptive to client message
- caching.
-
- 3. If the mailbox is deleted/renamed and a new mailbox with the same
- name is created at a later date, the server must either keep
- track of unique identifiers from the previous instance of the
- mailbox or assign a new UIDVALIDITY value to the new instance of
- the mailbox.
-
- 4. The combination of mailbox name, UIDVALIDITY, and UID must refer
- to a single, immutable (or expunged) message on that server
- forever. In particular, the internal date, RFC822.SIZE,
- envelope, body structure, and message texts (all BODY[...] fetch
- data items) MUST never change. This does not include message
- numbers, nor does it include attributes that can be set by a
- STORE command (such as FLAGS). When a message is expunged, its
- UID MUST NOT be reused under the same UIDVALIDITY value.
-
-2.3.1.2. Message Sequence Number Message Attribute
-
- A message sequence number is a relative position from 1 to the number
- of messages in the mailbox. This position MUST be ordered by
- ascending unique identifiers. As each new message is added, it is
- assigned a message sequence number that is 1 higher than the number
- of messages in the mailbox before that new message was added.
-
- Message sequence numbers can be reassigned during the session. For
- example, when a message is permanently removed (expunged) from the
- mailbox, the message sequence number for all subsequent messages is
- decremented. The number of messages in the mailbox is also
- decremented. Similarly, a new message can be assigned a message
- sequence number that was once held by some other message prior to an
- expunge.
-
- In addition to accessing messages by relative position in the
- mailbox, message sequence numbers can be used in mathematical
- calculations. For example, if an untagged "11 EXISTS" is received,
- and previously an untagged "8 EXISTS" was received, three new
- messages have arrived with message sequence numbers of 9, 10, and 11.
- As another example, if message 287 in a 523-message mailbox has UID
- 12345, there are exactly 286 messages that have lesser UIDs and 236
- messages that have greater UIDs.
-
-2.3.2. Flags Message Attribute
-
- A message has a list of zero or more named tokens, known as "flags",
- associated with it. A flag is set by its addition to this list and
- is cleared by its removal. There are two types of flags in
- IMAP4rev2: system flags and keywords. A flag of either type can be
- permanent or session-only.
-
- A system flag is a flag name that is predefined in this specification
- and begins with "\". Certain system flags (\Deleted and \Seen) have
- special semantics described elsewhere in this document. The
- currently defined system flags are:
-
- \Seen Message has been read
-
- \Answered Message has been answered
-
- \Flagged Message is "flagged" for urgent/special attention
-
- \Deleted Message is "deleted" for removal by later EXPUNGE
-
- \Draft Message has not completed composition (marked as a
- draft).
-
- \Recent This flag was in use in IMAP4rev1 and is now
- deprecated.
-
- A keyword is defined by the server implementation. Keywords do not
- begin with "\". Servers MAY permit the client to define new keywords
- in the mailbox (see the description of the PERMANENTFLAGS response
- code for more information). Some keywords that start with "$" are
- also defined in this specification.
-
- This document defines several keywords that were not originally
- defined in [RFC3501] but were found to be useful by client
- implementations. These keywords SHOULD be supported (allowed in
- SEARCH and allowed and preserved in APPEND, COPY, and MOVE commands)
- by server implementations:
-
- $Forwarded
- Message has been forwarded to another email address by being
- embedded within, or attached to a new message. An email client
- sets this keyword when it successfully forwards the message to
- another email address. Typical usage of this keyword is to show a
- different (or additional) icon for a message that has been
- forwarded. Once set, the flag SHOULD NOT be cleared.
-
- $MDNSent
- Message Disposition Notification [RFC8098] was generated and sent
- for this message. See [RFC3503] for more details on how this
- keyword is used and for requirements on clients and servers.
-
- $Junk
- The user (or a delivery agent on behalf of the user) may choose to
- mark a message as definitely containing junk ($Junk; see also the
- related keyword $NotJunk). The $Junk keyword can be used to mark,
- group, or hide undesirable messages (and such messages might be
- moved or deleted later). See [IMAP-KEYWORDS-REG] for more
- information.
-
- $NotJunk
- The user (or a delivery agent on behalf of the user) may choose to
- mark a message as definitely not containing junk ($NotJunk; see
- also the related keyword $Junk). The $NotJunk keyword can be used
- to mark, group, or show messages that the user wants to see. See
- [IMAP-KEYWORDS-REG] for more information.
-
- $Phishing
- The $Phishing keyword can be used by a delivery agent to mark a
- message as highly likely to be a phishing email. A message that's
- determined to be a phishing email by the delivery agent should
- also be considered a junk email and have the appropriate junk
- filtering applied, including setting the $Junk flag and placing
- the message in the \Junk special-use mailbox (see Section 7.3.1),
- if available.
-
- If both the $Phishing flag and the $Junk flag are set, the user
- agent should display an additional warning message to the user.
- Additionally, the user agent might display a warning, such as
- something of the form, "This message may be trying to steal your
- personal information," when the user clicks on any hyperlinks
- within the message.
-
- The requirement for both $Phishing and $Junk to be set before a
- user agent displays a warning is for better backwards
- compatibility with existing clients that understand the $Junk flag
- but not the $Phishing flag. This is so that when an unextended
- client removes the $Junk flag, an extended client will also show
- the correct state. See [IMAP-KEYWORDS-REG] for more information.
-
- $Junk and $NotJunk are mutually exclusive. If more than one of these
- is set for a message, the client MUST treat it as if none are set,
- and it SHOULD unset both of them on the IMAP server.
-
- Other registered keywords can be found in the "IMAP and JMAP
- Keywords" registry [IMAP-KEYWORDS-REG]. New keywords SHOULD be
- registered in this registry using the procedure specified in
- [RFC5788].
-
- A flag can be permanent or session-only on a per-flag basis.
- Permanent flags are those that the client can add or remove from the
- message flags permanently; that is, concurrent and subsequent
- sessions will see any change in permanent flags. Changes to session
- flags are valid only in that session.
-
-2.3.3. Internal Date Message Attribute
-
- An Internal Date message attribute is the internal date and time of
- the message on the server. This is not the date and time in the
- [RFC5322] header but rather a date and time that reflects when the
- message was received. In the case of messages delivered via [SMTP],
- this is the date and time of final delivery of the message as defined
- by [SMTP]. In the case of messages created by the IMAP4rev2 COPY or
- MOVE command, this SHOULD be the same as the Internal Date attribute
- of the source message. In the case of messages created by the
- IMAP4rev2 APPEND command, this SHOULD be the date and time as
- specified in the APPEND command description. All other cases are
- implementation defined.
-
-2.3.4. RFC822.SIZE Message Attribute
-
- RFC822.SIZE is the number of octets in the message when the message
- is expressed in [RFC5322] format. This size SHOULD match the result
- of a "FETCH BODY[]" command. If the message is internally stored in
- some other format, the server calculates the size and often stores it
- for later use to avoid the need for recalculation.
-
-2.3.5. Envelope Structure Message Attribute
-
- An envelope structure is a parsed representation of the [RFC5322]
- header of the message. Note that the IMAP envelope structure is not
- the same as an [SMTP] envelope.
-
-2.3.6. Body Structure Message Attribute
-
- A body structure is a parsed representation of the [MIME-IMB] body
- structure information of the message.
-
-2.4. Message Texts
-
- In addition to being able to fetch the full [RFC5322] text of a
- message, IMAP4rev2 permits the fetching of portions of the full
- message text. Specifically, it is possible to fetch the [RFC5322]
- message header, the [RFC5322] message body, a [MIME-IMB] body part,
- or a [MIME-IMB] header.
-
-3. State and Flow Diagram
-
- Once the connection between client and server is established, an
- IMAP4rev2 connection is in one of four states. The initial state is
- identified in the server greeting. Most commands are only valid in
- certain states. It is a protocol error for the client to attempt a
- command while the connection is in an inappropriate state, and the
- server will respond with a BAD or NO (depending upon server
- implementation) command completion result.
-
-3.1. Not Authenticated State
-
- In the not authenticated state, the client MUST supply authentication
- credentials before most commands will be permitted. This state is
- entered when a connection starts unless the connection has been pre-
- authenticated.
-
-3.2. Authenticated State
-
- In the authenticated state, the client is authenticated and MUST
- select a mailbox to access before commands that affect messages will
- be permitted. This state is entered when a pre-authenticated
- connection starts, when acceptable authentication credentials have
- been provided, after an error in selecting a mailbox, or after a
- successful CLOSE or UNSELECT command.
-
-3.3. Selected State
-
- In a selected state, a mailbox has been selected to access. This
- state is entered when a mailbox has been successfully selected.
-
-3.4. Logout State
-
- In the logout state, the connection is being terminated. This state
- can be entered as a result of a client request (via the LOGOUT
- command) or by unilateral action on the part of either the client or
- the server.
-
- If the client requests the logout state, the server MUST send an
- untagged BYE response and a tagged OK response to the LOGOUT command
- before the server closes the connection; and the client MUST read the
- tagged OK response to the LOGOUT command before the client closes the
- connection.
-
- A server SHOULD NOT unilaterally close the connection without first
- sending an untagged BYE response that contains the reason for doing
- so. A client SHOULD NOT unilaterally close the connection; instead,
- it SHOULD issue a LOGOUT command. If the server detects that the
- client has unilaterally closed the connection, the server MAY omit
- the untagged BYE response and simply close its connection.
-
- +----------------------+
- |connection established|
- +----------------------+
- ||
- \/
- +--------------------------------------+
- | server greeting |
- +--------------------------------------+
- || (1) || (2) || (3)
- \/ || ||
- +-----------------+ || ||
- |Not Authenticated| || ||
- +-----------------+ || ||
- || (7) || (4) || ||
- || \/ \/ ||
- || +----------------+ ||
- || | Authenticated |<=++ ||
- || +----------------+ || ||
- || || (7) || (5) || (6) ||
- || || \/ || ||
- || || +--------+ || ||
- || || |Selected|==++ ||
- || || +--------+ ||
- || || || (7) ||
- \/ \/ \/ \/
- +--------------------------------------+
- | Logout |
- +--------------------------------------+
- ||
- \/
- +-------------------------------+
- |both sides close the connection|
- +-------------------------------+
-
- Legend for the above diagram:
-
- (1) connection without pre-authentication (OK greeting)
- (2) pre-authenticated connection (PREAUTH greeting)
- (3) rejected connection (BYE greeting)
- (4) successful LOGIN or AUTHENTICATE command
- (5) successful SELECT or EXAMINE command
- (6) CLOSE or UNSELECT command, unsolicited CLOSED response code, or
- failed SELECT or EXAMINE command
- (7) LOGOUT command, server shutdown, or connection closed
-
-4. Data Formats
-
- IMAP4rev2 uses textual commands and responses. Data in IMAP4rev2 can
- be in one of several forms: atom, number, string, parenthesized list,
- or NIL. Note that a particular data item may take more than one
- form; for example, a data item defined as using "astring" syntax may
- be either an atom or a string.
-
-4.1. Atom
-
- An atom consists of one or more non-special characters.
-
-4.1.1. Sequence Set and UID Set
-
- A set of messages can be referenced by a sequence set containing
- either message sequence numbers or unique identifiers. See Section 9
- for details. A sequence set can contain ranges of sequence numbers
- (such as "5:50"), an enumeration of specific sequence numbers, or a
- combination of the above. A sequence set can use the special symbol
- "*" to represent the maximum sequence number in the mailbox. A
- sequence set never contains unique identifiers.
-
- A "UID set" is similar to the sequence set, but uses unique
- identifiers instead of message sequence numbers, and is not permitted
- to contain the special symbol "*".
-
-4.2. Number
-
- A number consists of one or more digit characters and represents a
- numeric value.
-
-4.3. String
-
- A string is in one of three forms: synchronizing literal, non-
- synchronizing literal, or quoted string. The synchronizing literal
- form is the general form of a string, without limitation on the
- characters the string may include. The non-synchronizing literal
- form is also the general form, but it has a length restriction. The
- quoted string form is an alternative that avoids the overhead of
- processing a literal, but has limitations on the characters that may
- be used.
-
- When the distinction between synchronizing and non-synchronizing
- literals is not important, this document only uses the term
- "literal".
-
- A synchronizing literal is a sequence of zero or more octets
- (including CR and LF), prefix-quoted with an octet count in the form
- of an open brace ("{"), the number of octets, a close brace ("}"),
- and a CRLF. In the case of synchronizing literals transmitted from
- server to client, the CRLF is immediately followed by the octet data.
- In the case of synchronizing literals transmitted from client to
- server, the client MUST wait to receive a command continuation
- request (described later in this document) before sending the octet
- data (and the remainder of the command).
-
- The non-synchronizing literal is an alternative form of synchronizing
- literal and may be used from client to server anywhere a
- synchronizing literal is permitted. The non-synchronizing literal
- form MUST NOT be sent from server to client. The non-synchronizing
- literal is distinguished from the synchronizing literal by having a
- plus ("+") between the octet count and the closing brace ("}"). The
- server does not generate a command continuation request in response
- to a non-synchronizing literal, and clients are not required to wait
- before sending the octets of a non-synchronizing literal. Unless
- otherwise specified in an IMAP extension, non-synchronizing literals
- MUST NOT be larger than 4096 octets. Any literal larger than 4096
- bytes MUST be sent as a synchronizing literal. (Non-synchronizing
- literals defined in this document are the same as non-synchronizing
- literals defined by the LITERAL- extension from [RFC7888]. See that
- document for details on how to handle invalid non-synchronizing
- literals longer than 4096 octets and for interaction with other IMAP
- extensions.)
-
- A quoted string is a sequence of zero or more Unicode characters,
- excluding CR and LF, encoded in UTF-8, with double quote (<">)
- characters at each end.
-
- The empty string is represented as "" (a quoted string with zero
- characters between double quotes), as {0} followed by a CRLF (a
- synchronizing literal with an octet count of 0), or as {0+} followed
- by a CRLF (a non-synchronizing literal with an octet count of 0).
-
- Note: Even if the octet count is 0, a client transmitting a
- synchronizing literal MUST wait to receive a command continuation
- request.
-
-4.3.1. 8-Bit and Binary Strings
-
- 8-bit textual and binary mail is supported through the use of a
- [MIME-IMB] content transfer encoding. IMAP4rev2 implementations MAY
- transmit 8-bit or multi-octet characters in literals but SHOULD do so
- only when the [CHARSET] is identified.
-
- IMAP4rev2 is compatible with [I18N-HDRS]. As a result, the
- identified charset for header-field values with 8-bit content is
- UTF-8 [UTF-8]. IMAP4rev2 implementations MUST accept and MAY
- transmit [UTF-8] text in quoted-strings as long as the string does
- not contain NUL, CR, or LF. This differs from IMAP4rev1
- implementations.
-
- Although a BINARY content transfer encoding is defined, unencoded
- binary strings are not permitted, unless returned in a in
- response to a BINARY.PEEK[]<> or
- BINARY[]<> FETCH data item. A "binary
- string" is any string with NUL characters. A string with an
- excessive amount of CTL characters MAY also be considered to be
- binary. Unless returned in response to BINARY.PEEK[...]/BINARY[...]
- FETCH, client and server implementations MUST encode binary data into
- a textual form, such as base64, before transmitting the data.
-
-4.4. Parenthesized List
-
- Data structures are represented as a "parenthesized list"; a sequence
- of data items, delimited by space, and bounded at each end by
- parentheses. A parenthesized list can contain other parenthesized
- lists, using multiple levels of parentheses to indicate nesting.
-
- The empty list is represented as () -- a parenthesized list with no
- members.
-
-4.5. NIL
-
- The special form "NIL" represents the non-existence of a particular
- data item that is represented as a string or parenthesized list, as
- distinct from the empty string "" or the empty parenthesized list ().
-
- | Note: NIL is never used for any data item that takes the form
- | of an atom. For example, a mailbox name of "NIL" is a mailbox
- | named NIL as opposed to a non-existent mailbox name. This is
- | because mailbox uses "astring" syntax, which is an atom or a
- | string. Conversely, an addr-name of NIL is a non-existent
- | personal name, because addr-name uses "nstring" syntax, which
- | is NIL or a string, but never an atom.
-
- Examples:
-
- The following LIST response:
-
- * LIST () "/" NIL
-
- is equivalent to:
-
- * LIST () "/" "NIL"
-
- as LIST response ABNF is using "astring" for mailbox name.
-
- However, the following response:
-
- * FETCH 1 (BODY[1] NIL)
-
- is not equivalent to:
-
- * FETCH 1 (BODY[1] "NIL")
-
- The former indicates absence of the body part, while the latter means
- that it contains a string with the three characters "NIL".
-
-5. Operational Considerations
-
- The following rules are listed here to ensure that all IMAP4rev2
- implementations interoperate properly.
-
-5.1. Mailbox Naming
-
- In IMAP4rev2, mailbox names are encoded in Net-Unicode [NET-UNICODE]
- (this differs from IMAP4rev1). Client implementations MAY attempt to
- create Net-Unicode mailbox names and MUST interpret any 8-bit mailbox
- names returned by LIST as [NET-UNICODE]. Server implementations MUST
- prohibit the creation of 8-bit mailbox names that do not comply with
- Net-Unicode. However, servers MAY accept a denormalized UTF-8
- mailbox name and convert it to Unicode Normalization Form C (NFC) (as
- per Net-Unicode requirements) prior to mailbox creation. Servers
- that choose to accept such denormalized UTF-8 mailbox names MUST
- accept them in all IMAP commands that have a mailbox name parameter.
- In particular, SELECT must open the same mailbox that was
- successfully created with CREATE , even if is a
- denormalized UTF-8 mailbox name.
-
- The case-insensitive mailbox name INBOX is a special name reserved to
- mean "the primary mailbox for this user on this server". (Note that
- this special name might not exist on some servers for some users, for
- example, if the user has no access to personal namespace.) The
- interpretation of all other names is implementation dependent.
-
- In particular, this specification takes no position on case
- sensitivity in non-INBOX mailbox names. Some server implementations
- are fully case sensitive in ASCII range; others preserve the case of
- a newly created name but otherwise are case insensitive; and yet
- others coerce names to a particular case. Client implementations
- must be able to interact with any of these.
-
- There are certain client considerations when creating a new mailbox
- name:
-
- 1. Any character that is one of the atom-specials (see "Formal
- Syntax" in Section 9) will require that the mailbox name be
- represented as a quoted string or literal.
-
- 2. CTL and other non-graphic characters are difficult to represent
- in a user interface and are best avoided. Servers MAY refuse to
- create mailbox names containing Unicode CTL characters.
-
- 3. Although the list-wildcard characters ("%" and "*") are valid in
- a mailbox name, it is difficult to use such mailbox names with
- the LIST command due to the conflict with wildcard
- interpretation.
-
- 4. Usually, a character (determined by the server implementation) is
- reserved to delimit levels of hierarchy.
-
- 5. Two characters, "#" and "&", have meanings by convention and
- should be avoided except when used in that convention. See
- Section 5.1.2.1 and Appendix A.1, respectively.
-
-5.1.1. Mailbox Hierarchy Naming
-
- If it is desired to export hierarchical mailbox names, mailbox names
- MUST be left-to-right hierarchical, using a single ASCII character to
- separate levels of hierarchy. The same hierarchy separator character
- is used for all levels of hierarchy within a single name.
-
-5.1.2. Namespaces
-
- Personal Namespace:
- A namespace that the server considers within the personal scope of
- the authenticated user on a particular connection. Typically,
- only the authenticated user has access to mailboxes in their
- Personal Namespace. It is the part of the namespace that belongs
- to the user and is allocated for mailboxes. If an INBOX exists
- for a user, it MUST appear within the user's Personal Namespace.
- In the typical case, there SHOULD be only one Personal Namespace
- per user on a server.
-
- Other Users' Namespace:
- A namespace that consists of mailboxes from the Personal
- Namespaces of other users. To access mailboxes in the Other
- Users' Namespace, the currently authenticated user MUST be
- explicitly granted access rights. For example, it is common for a
- manager to grant to their administrative support staff access
- rights to their mailbox. In the typical case, there SHOULD be
- only one Other Users' Namespace per user on a server.
-
- Shared Namespace:
- A namespace that consists of mailboxes that are intended to be
- shared amongst users and do not exist within a user's Personal
- Namespace.
-
- The namespaces a server uses MAY differ on a per-user basis.
-
-5.1.2.1. Historic Mailbox Namespace Naming Convention
-
- By convention, the first hierarchical element of any mailbox name
- that begins with "#" identifies the "namespace" of the remainder of
- the name. This makes it possible to disambiguate between different
- types of mailbox stores, each of which have their own namespaces.
-
- For example, implementations that offer access to USENET
- newsgroups MAY use the "#news" namespace to partition the USENET
- newsgroup namespace from that of other mailboxes. Thus, the
- comp.mail.misc newsgroup would have a mailbox name of
- "#news.comp.mail.misc", and the name "comp.mail.misc" can refer to
- a different object (e.g., a user's private mailbox).
-
- Namespaces that include the "#" character are not IMAP URL [IMAP-URL]
- friendly and require the "#" character to be represented as %23 when
- within URLs. As such, server implementors MAY instead consider using
- namespace prefixes that do not contain the "#" character.
-
-5.1.2.2. Common Namespace Models
-
- The previous version of this protocol did not define a default server
- namespace. Two common namespace models have evolved:
-
- The "Personal Mailbox" model, in which the default namespace that is
- presented consists of only the user's personal mailboxes. To access
- shared mailboxes, the user must use an escape mechanism to reach
- another namespace.
-
- The "Complete Hierarchy" model, in which the default namespace that
- is presented includes the user's personal mailboxes along with any
- other mailboxes they have access to.
-
-5.2. Mailbox Size and Message Status Updates
-
- At any time, a server can send data that the client did not request.
- Sometimes, such behavior is required by this specification and/or
- extensions. For example, agents other than the server may add
- messages to the mailbox (e.g., new message delivery); change the
- flags of the messages in the mailbox (e.g., simultaneous access to
- the same mailbox by multiple agents); or even remove messages from
- the mailbox. A server MUST send mailbox size updates automatically
- if a mailbox size change is observed during the processing of a
- command. A server SHOULD send message flag updates automatically,
- without requiring the client to request such updates explicitly.
-
- Special rules exist for server notification of a client about the
- removal of messages to prevent synchronization errors; see the
- description of the EXPUNGE response (Section 7.5.1) for more detail.
- In particular, it is NOT permitted to send an EXISTS response that
- would reduce the number of messages in the mailbox; only the EXPUNGE
- response can do this.
-
- Regardless of what implementation decisions a client makes on
- remembering data from the server, a client implementation MUST
- remember mailbox size updates. It MUST NOT assume that any command
- after the initial mailbox selection will return the size of the
- mailbox.
-
-5.3. Response When No Command in Progress
-
- Server implementations are permitted to send an untagged response
- (except for EXPUNGE) while there is no command in progress. Server
- implementations that send such responses MUST deal with flow control
- considerations. Specifically, they MUST either (1) verify that the
- size of the data does not exceed the underlying transport's available
- window size or (2) use non-blocking writes.
-
-5.4. Autologout Timer
-
- If a server has an inactivity autologout timer that applies to
- sessions after authentication, the duration of that timer MUST be at
- least 30 minutes. The receipt of any command from the client during
- that interval resets the autologout timer.
-
- Note that this specification doesn't have any restrictions on an
- autologout timer used before successful client authentication. In
- particular, servers are allowed to use a shortened pre-authentication
- timer to protect themselves from Denial-of-Service attacks.
-
-5.5. Multiple Commands in Progress (Command Pipelining)
-
- The client MAY send another command without waiting for the
- completion result response of a command, subject to ambiguity rules
- (see below) and flow control constraints on the underlying data
- stream. Similarly, a server MAY begin processing another command
- before processing the current command to completion, subject to
- ambiguity rules. However, any command continuation request responses
- and command continuations MUST be negotiated before any subsequent
- command is initiated.
-
- The exception is if an ambiguity would result because of a command
- that would affect the results of other commands. If the server
- detects a possible ambiguity, it MUST execute commands to completion
- in the order given by the client.
-
- The most obvious example of ambiguity is when a command would affect
- the results of another command. One example is a FETCH that would
- cause \Seen flags to be set and a SEARCH UNSEEN command.
-
- A non-obvious ambiguity occurs with commands that permit an untagged
- EXPUNGE response (commands other than FETCH, STORE, and SEARCH),
- since an untagged EXPUNGE response can invalidate sequence numbers in
- a subsequent command. This is not a problem for FETCH, STORE, or
- SEARCH commands because servers are prohibited from sending EXPUNGE
- responses while any of those commands are in progress. Therefore, if
- the client sends any command other than FETCH, STORE, or SEARCH, it
- MUST wait for the completion result response before sending a command
- with message sequence numbers.
-
- Note: EXPUNGE responses are permitted while UID FETCH, UID STORE,
- and UID SEARCH are in progress. If the client sends a UID
- command, it MUST wait for a completion result response before
- sending a command that uses message sequence numbers (this may
- include UID SEARCH). Any message sequence numbers in an argument
- to UID SEARCH are associated with messages prior to the effect of
- any untagged EXPUNGE responses returned by the UID SEARCH.
-
- For example, the following non-waiting command sequences are invalid:
-
- FETCH + NOOP + STORE
-
- STORE + COPY + FETCH
-
- COPY + COPY
-
- The following are examples of valid non-waiting command sequences:
-
- FETCH + STORE + SEARCH + NOOP
-
- STORE + COPY + EXPUNGE
-
- UID SEARCH + UID SEARCH may be valid or invalid as a non-waiting
- command sequence, depending upon whether or not the second UID SEARCH
- contains message sequence numbers.
-
- Use of a SEARCH result variable (see Section 6.4.4.1) creates direct
- dependency between two commands. See Section 6.4.4.2 for more
- considerations about pipelining such dependent commands.
-
-6. Client Commands
-
- IMAP4rev2 commands are described in this section. Commands are
- organized by the state in which the command is permitted. Commands
- that are permitted in multiple states are listed in the minimum
- permitted state (for example, commands valid in authenticated and
- selected states are listed in the authenticated state commands).
-
- Command arguments, identified by "Arguments:" in the command
- descriptions below, are described by function, not by syntax. The
- precise syntax of command arguments is described in "Formal Syntax"
- (Section 9).
-
- Some commands cause specific server responses to be returned; these
- are identified by "Responses:" in the command descriptions below.
- See the response descriptions in "Responses" (Section 7) for
- information on these responses and in "Formal Syntax" (Section 9) for
- the precise syntax of these responses. It is possible for server
- data to be transmitted as a result of any command. Thus, commands
- that do not specifically require server data specify "no specific
- responses for this command" instead of "none".
-
- The "Result:" in the command description refers to the possible
- tagged status responses to a command and any special interpretation
- of these status responses.
-
- The state of a connection is only changed by successful commands that
- are documented as changing state. A rejected command (BAD response)
- never changes the state of the connection or of the selected mailbox.
- A failed command (NO response) generally does not change the state of
- the connection or of the selected mailbox, with the exception of the
- SELECT and EXAMINE commands.
-
-6.1. Client Commands - Any State
-
- The following commands are valid in any state: CAPABILITY, NOOP, and
- LOGOUT.
-
-6.1.1. CAPABILITY Command
-
- Arguments: none
-
- Responses: REQUIRED untagged response: CAPABILITY
-
- Result: OK - capability completed
- BAD - arguments invalid
-
- The CAPABILITY command requests a listing of capabilities (e.g.,
- extensions and/or modifications of server behavior) that the server
- supports. The server MUST send a single untagged CAPABILITY response
- with "IMAP4rev2" as one of the listed capabilities before the
- (tagged) OK response.
-
- A capability name that begins with "AUTH=" indicates that the server
- supports that particular authentication mechanism as defined in the
- Simple Authentication and Security Layer (SASL) [SASL]. All such
- names are, by definition, part of this specification.
-
- Other capability names refer to extensions, revisions, or amendments
- to this specification. See the documentation of the CAPABILITY
- response in Section 7.2.2 for additional information. If IMAP4rev1
- capability is not advertised, no capabilities, beyond the base
- IMAP4rev2 set defined in this specification, are enabled without
- explicit client action to invoke the capability. If both IMAP4rev1
- and IMAP4rev2 capabilities are advertised, no capabilities, beyond
- the base IMAP4rev1 set specified in [RFC3501], are enabled without
- explicit client action to invoke the capability.
-
- Client and server implementations MUST implement the STARTTLS
- (Section 6.2.1) and LOGINDISABLED capabilities on cleartext ports.
- Client and server implementations MUST also implement AUTH=PLAIN
- (described in [PLAIN]) capability on both cleartext and Implicit TLS
- ports. See the Security Considerations (Section 11) for important
- information.
-
- Unless otherwise specified, all registered extensions to IMAP4rev1
- are also valid extensions to IMAP4rev2.
-
- Example:
-
- C: abcd CAPABILITY
- S: * CAPABILITY IMAP4rev2 STARTTLS AUTH=GSSAPI
- LOGINDISABLED
- S: abcd OK CAPABILITY completed
- C: efgh STARTTLS
- S: efgh OK STARTTLS completed
-
- C: ijkl CAPABILITY
- S: * CAPABILITY IMAP4rev2 AUTH=GSSAPI AUTH=PLAIN
- S: ijkl OK CAPABILITY completed
-
-6.1.2. NOOP Command
-
- Arguments: none
-
- Responses: no specific responses for this command (but see below)
-
- Result: OK - noop completed
- BAD - command unknown or arguments invalid
-
- The NOOP command always succeeds. It does nothing.
-
- Since any command can return a status update as untagged data, the
- NOOP command can be used as a periodic poll for new messages or
- message status updates during a period of inactivity (the IDLE
- command; see Section 6.3.13) should be used instead of NOOP if real-
- time updates to mailbox state are desirable). The NOOP command can
- also be used to reset any inactivity autologout timer on the server.
-
- Example:
-
- C: a002 NOOP
- S: a002 OK NOOP completed
- . . .
- C: a047 NOOP
- S: * 22 EXPUNGE
- S: * 23 EXISTS
- S: * 14 FETCH (UID 1305 FLAGS (\Seen \Deleted))
- S: a047 OK NOOP completed
-
-6.1.3. LOGOUT Command
-
- Arguments: none
-
- Responses: REQUIRED untagged response: BYE
-
- Result: OK - logout completed
- BAD - command unknown or arguments invalid
-
- The LOGOUT command informs the server that the client is done with
- the connection. The server MUST send a BYE untagged response before
- the (tagged) OK response, and then close the network connection.
-
- Example:
-
- C: A023 LOGOUT
- S: * BYE IMAP4rev2 Server logging out
- S: A023 OK LOGOUT completed
- (Server and client then close the connection)
-
-6.2. Client Commands - Not Authenticated State
-
- In the not authenticated state, the AUTHENTICATE or LOGIN command
- establishes authentication and enters the authenticated state. The
- AUTHENTICATE command provides a general mechanism for a variety of
- authentication techniques, privacy protection, and integrity
- checking, whereas the LOGIN command uses a conventional user name and
- plaintext password pair and has no means of establishing privacy
- protection or integrity checking.
-
- The STARTTLS command is an alternative form of establishing session
- privacy protection and integrity checking but does not by itself
- establish authentication or enter the authenticated state.
-
- Server implementations MAY allow access to certain mailboxes without
- establishing authentication. This can be done by means of the
- ANONYMOUS [SASL] authenticator described in [ANONYMOUS]. An older
- convention is a LOGIN command using the userid "anonymous"; in this
- case, a password is required although the server may choose to accept
- any password. The restrictions placed on anonymous users are
- implementation dependent.
-
- Once authenticated (including as anonymous), it is not possible to
- re-enter not authenticated state.
-
- In addition to the universal commands (CAPABILITY, NOOP, and LOGOUT),
- the following commands are valid in the not authenticated state:
- STARTTLS, AUTHENTICATE, and LOGIN. See the Security Considerations
- (Section 11) for important information about these commands.
-
-6.2.1. STARTTLS Command
-
- Arguments: none
-
- Responses: no specific response for this command
-
- Result: OK - starttls completed, begin TLS negotiation
- NO - TLS negotiation can't be initiated, due to server
- configuration error
- BAD - STARTTLS received after a successful TLS
- negotiation or arguments invalid
-
- Note that the STARTTLS command is available only on cleartext ports.
- The server MUST always respond with a tagged BAD response when the
- STARTTLS command is received on an Implicit TLS port.
-
- A TLS [TLS-1.3] negotiation begins immediately after the CRLF at the
- end of the tagged OK response from the server. Once a client issues
- a STARTTLS command, it MUST NOT issue further commands until a server
- response is seen and the TLS negotiation is complete. Some past
- server implementations incorrectly implemented STARTTLS processing
- and are known to contain STARTTLS plaintext command injection
- vulnerability [CERT-555316]. In order to avoid this vulnerability,
- server implementations MUST do one of the following if any data is
- received in the same TCP buffer after the CRLF that starts the
- STARTTLS command:
-
- 1. Extra data from the TCP buffer is interpreted as the beginning of
- the TLS handshake. (If the data is in cleartext, this will
- result in the TLS handshake failing.)
-
- 2. Extra data from the TCP buffer is thrown away.
-
- Note that the first option is friendlier to clients that pipeline the
- beginning of the STARTTLS command with TLS handshake data.
-
- After successful TLS negotiation, the server remains in the non-
- authenticated state, even if client credentials are supplied during
- the TLS negotiation. This does not preclude an authentication
- mechanism such as EXTERNAL (defined in [SASL]) from using client
- identity determined by the TLS negotiation.
-
- Once TLS has been started, the client MUST discard cached information
- about server capabilities and SHOULD reissue the CAPABILITY command.
- This is necessary to protect against active attacks that alter the
- capabilities list prior to STARTTLS. The server MAY advertise
- different capabilities and, in particular, SHOULD NOT advertise the
- STARTTLS capability, after a successful STARTTLS command.
-
- Example:
-
- C: a001 CAPABILITY
- S: * CAPABILITY IMAP4rev2 STARTTLS LOGINDISABLED
- S: a001 OK CAPABILITY completed
- C: a002 STARTTLS
- S: a002 OK Begin TLS negotiation now
-
- C: a003 CAPABILITY
- S: * CAPABILITY IMAP4rev2 AUTH=PLAIN
- S: a003 OK CAPABILITY completed
- C: a004 AUTHENTICATE PLAIN dGVzdAB0ZXN0AHRlc3Q=
- S: a004 OK Success (tls protection)
-
-6.2.2. AUTHENTICATE Command
-
- Arguments: SASL authentication mechanism name
-
- OPTIONAL initial response
-
- Responses: continuation data can be requested
-
- Result: OK - authenticate completed, now in authenticated
- state
- NO - authenticate failure: unsupported authentication
- mechanism, credentials rejected
- BAD - command unknown or arguments invalid,
- authentication exchange canceled
-
- The AUTHENTICATE command indicates a [SASL] authentication mechanism
- to the server. If the server supports the requested authentication
- mechanism, it performs an authentication protocol exchange to
- authenticate and identify the client. It MAY also negotiate an
- OPTIONAL security layer for subsequent protocol interactions. If the
- requested authentication mechanism is not supported, the server
- SHOULD reject the AUTHENTICATE command by sending a tagged NO
- response.
-
- The AUTHENTICATE command supports the optional "initial response"
- feature defined in Section 4 of [SASL]. The client doesn't need to
- use it. If a SASL mechanism supports "initial response", but it is
- not specified by the client, the server handles it as specified in
- Section 3 of [SASL].
-
- The service name specified by this protocol's profile of [SASL] is
- "imap".
-
- The authentication protocol exchange consists of a series of server
- challenges and client responses that are specific to the
- authentication mechanism. A server challenge consists of a command
- continuation request response with the "+" token followed by a
- base64-encoded (see Section 4 of [RFC4648]) string. The client
- response consists of a single line consisting of a base64-encoded
- string. If the client wishes to cancel an authentication exchange,
- it issues a line consisting of a single "*". If the server receives
- such a response, or if it receives an invalid base64 string (e.g.,
- characters outside the base64 alphabet or non-terminal "="), it MUST
- reject the AUTHENTICATE command by sending a tagged BAD response.
-
- As with any other client response, the initial response MUST be
- encoded as base64. It also MUST be transmitted outside of a quoted
- string or literal. To send a zero-length initial response, the
- client MUST send a single pad character ("="). This indicates that
- the response is present, but it is a zero-length string.
-
- When decoding the base64 data in the initial response, decoding
- errors MUST be treated as in any normal SASL client response, i.e.,
- with a tagged BAD response. In particular, the server should check
- for any characters not explicitly allowed by the base64 alphabet, as
- well as any sequence of base64 characters that contains the pad
- character ('=') anywhere other than the end of the string (e.g.,
- "=AAA" and "AAA=BBB" are not allowed).
-
- If the client uses an initial response with a SASL mechanism that
- does not support an initial response, the server MUST reject the
- command with a tagged BAD response.
-
- If a security layer is negotiated through the [SASL] authentication
- exchange, it takes effect immediately following the CRLF that
- concludes the authentication exchange for the client and the CRLF of
- the tagged OK response for the server.
-
- While client and server implementations MUST implement the
- AUTHENTICATE command itself, it is not required to implement any
- authentication mechanisms other than the PLAIN mechanism described in
- [PLAIN]. Also, an authentication mechanism is not required to
- support any security layers.
-
- Note: a server implementation MUST implement a configuration in
- which it does NOT permit any plaintext password mechanisms, unless
- the STARTTLS command has been negotiated, TLS has been negotiated
- on an Implicit TLS port, or some other mechanism that protects the
- session from password snooping has been provided. Server sites
- SHOULD NOT use any configuration that permits a plaintext password
- mechanism without such a protection mechanism against password
- snooping. Client and server implementations SHOULD implement
- additional [SASL] mechanisms that do not use plaintext passwords,
- such as the GSSAPI mechanism described in [RFC4752], the SCRAM-
- SHA-256/SCRAM-SHA-256-PLUS [SCRAM-SHA-256] mechanisms, and/or the
- EXTERNAL [SASL] mechanism for mutual TLS authentication. (Note
- that the SASL framework allows for the creation of SASL mechanisms
- that support 2-factor authentication (2FA); however, none are
- fully ready to be recommended by this document.)
-
- Servers and clients can support multiple authentication mechanisms.
- The server SHOULD list its supported authentication mechanisms in the
- response to the CAPABILITY command so that the client knows which
- authentication mechanisms to use.
-
- A server MAY include a CAPABILITY response code in the tagged OK
- response of a successful AUTHENTICATE command in order to send
- capabilities automatically. It is unnecessary for a client to send a
- separate CAPABILITY command if it recognizes these automatic
- capabilities. This should only be done if a security layer was not
- negotiated by the AUTHENTICATE command, because the tagged OK
- response as part of an AUTHENTICATE command is not protected by
- encryption/integrity checking. [SASL] requires the client to re-
- issue a CAPABILITY command in this case. The server MAY advertise
- different capabilities after a successful AUTHENTICATE command.
-
- If an AUTHENTICATE command fails with a NO response, the client MAY
- try another authentication mechanism by issuing another AUTHENTICATE
- command. It MAY also attempt to authenticate by using the LOGIN
- command (see Section 6.2.3 for more detail). In other words, the
- client MAY request authentication types in decreasing order of
- preference, with the LOGIN command as a last resort.
-
- The authorization identity passed from the client to the server
- during the authentication exchange is interpreted by the server as
- the user name whose privileges the client is requesting.
-
- Example:
-
- S: * OK [CAPABILITY IMAP4rev2 STARTTLS AUTH=GSSAPI]
- Capabilities
- C: A001 AUTHENTICATE GSSAPI
- S: +
- C: YIIB+wYJKoZIhvcSAQICAQBuggHqMIIB5qADAgEFoQMCAQ6iBw
- MFACAAAACjggEmYYIBIjCCAR6gAwIBBaESGxB1Lndhc2hpbmd0
- b24uZWR1oi0wK6ADAgEDoSQwIhsEaW1hcBsac2hpdmFtcy5jYW
- Mud2FzaGluZ3Rvbi5lZHWjgdMwgdCgAwIBAaEDAgEDooHDBIHA
- cS1GSa5b+fXnPZNmXB9SjL8Ollj2SKyb+3S0iXMljen/jNkpJX
- AleKTz6BQPzj8duz8EtoOuNfKgweViyn/9B9bccy1uuAE2HI0y
- C/PHXNNU9ZrBziJ8Lm0tTNc98kUpjXnHZhsMcz5Mx2GR6dGknb
- I0iaGcRerMUsWOuBmKKKRmVMMdR9T3EZdpqsBd7jZCNMWotjhi
- vd5zovQlFqQ2Wjc2+y46vKP/iXxWIuQJuDiisyXF0Y8+5GTpAL
- pHDc1/pIGmMIGjoAMCAQGigZsEgZg2on5mSuxoDHEA1w9bcW9n
- FdFxDKpdrQhVGVRDIzcCMCTzvUboqb5KjY1NJKJsfjRQiBYBdE
- NKfzK+g5DlV8nrw81uOcP8NOQCLR5XkoMHC0Dr/80ziQzbNqhx
- O6652Npft0LQwJvenwDI13YxpwOdMXzkWZN/XrEqOWp6GCgXTB
- vCyLWLlWnbaUkZdEYbKHBPjd8t/1x5Yg==
- S: + YGgGCSqGSIb3EgECAgIAb1kwV6ADAgEFoQMCAQ+iSzBJoAMC
- AQGiQgRAtHTEuOP2BXb9sBYFR4SJlDZxmg39IxmRBOhXRKdDA0
- uHTCOT9Bq3OsUTXUlk0CsFLoa8j+gvGDlgHuqzWHPSQg==
- C:
- S: + YDMGCSqGSIb3EgECAgIBAAD/////6jcyG4GE3KkTzBeBiVHe
- ceP2CWY0SR0fAQAgAAQEBAQ=
- C: YDMGCSqGSIb3EgECAgIBAAD/////3LQBHXTpFfZgrejpLlLImP
- wkhbfa2QteAQAgAG1yYwE=
- S: A001 OK GSSAPI authentication successful
-
- The following example demonstrates the use of an initial response.
-
- Example:
-
- S: * OK [CAPABILITY IMAP4rev2 STARTTLS AUTH=GSSAPI
- LOGINDISABLED] Server ready
- C: A01 STARTTLS
- S: A01 OK STARTTLS completed
-
- C: A02 CAPABILITY
- S: * CAPABILITY IMAP4rev2 AUTH=GSSAPI AUTH=PLAIN
- S: A02 OK CAPABILITY completed
- C: A03 AUTHENTICATE PLAIN dGVzdAB0ZXN0AHRlc3Q=
- S: A03 OK Success (tls protection)
-
- Note that because the initial response is optional, the following
- negotiation (which does not use the initial response) is still valid
- and MUST be supported by the server:
-
- ... client connects to server and negotiates a TLS
- protection layer ...
- C: C01 CAPABILITY
- S: * CAPABILITY IMAP4rev2 AUTH=PLAIN
- S: C01 OK Completed
- C: A01 AUTHENTICATE PLAIN
- S: +
- C: dGVzdAB0ZXN0AHRlc3Q=
- S: A01 OK Success (tls protection)
-
- Note that in the above example there is a space following the "+"
- from the server.
-
- The following is an example authentication using the SASL EXTERNAL
- mechanism (defined in [SASL]) under a TLS protection layer and an
- empty initial response:
-
- ... client connects to server and negotiates a TLS
- protection layer ...
- C: C01 CAPABILITY
- S: * CAPABILITY IMAP4rev2 AUTH=PLAIN AUTH=EXTERNAL
- S: C01 OK Completed
- C: A01 AUTHENTICATE EXTERNAL =
- S: A01 OK Success (tls protection)
-
- Note: The line breaks within server challenges and client responses
- are for editorial clarity and are not in real authenticators.
-
-6.2.3. LOGIN Command
-
- Arguments: user name
-
- password
-
- Responses: no specific responses for this command
-
- Result: OK - login completed, now in authenticated state
- NO - login failure: user name or password rejected
- BAD - command unknown or arguments invalid
-
- The LOGIN command identifies the client to the server and carries the
- plaintext password authenticating this user. The LOGIN command
- SHOULD NOT be used except as a last resort (after attempting and
- failing to authenticate using the AUTHENTICATE command one or more
- times), and it is recommended that client implementations have a
- means to disable any automatic use of the LOGIN command.
-
- A server MAY include a CAPABILITY response code in the tagged OK
- response to a successful LOGIN command in order to send capabilities
- automatically. It is unnecessary for a client to send a separate
- CAPABILITY command if it recognizes these automatic capabilities.
-
- Example:
-
- C: a001 LOGIN SMITH SESAME
- S: a001 OK LOGIN completed
-
- Note: Use of the LOGIN command over an insecure network (such as the
- Internet) is a security risk, because anyone monitoring network
- traffic can obtain plaintext passwords. For that reason, clients
- MUST NOT use LOGIN on unsecure networks.
-
- Unless the client is accessing IMAP service on an Implicit TLS port
- [RFC8314], the STARTTLS command has been negotiated, or some other
- mechanism that protects the session from password snooping has been
- provided, a server implementation MUST implement a configuration in
- which it advertises the LOGINDISABLED capability and does NOT permit
- the LOGIN command. Server sites SHOULD NOT use any configuration
- that permits the LOGIN command without such a protection mechanism
- against password snooping. A client implementation MUST NOT send a
- LOGIN command if the LOGINDISABLED capability is advertised.
-
-6.3. Client Commands - Authenticated State
-
- In the authenticated state, commands that manipulate mailboxes as
- atomic entities are permitted. Of these commands, SELECT and EXAMINE
- will select a mailbox for access and enter the selected state.
-
- In addition to the universal commands (CAPABILITY, NOOP, and LOGOUT),
- the following commands are valid in the authenticated state: ENABLE,
- SELECT, EXAMINE, NAMESPACE, CREATE, DELETE, RENAME, SUBSCRIBE,
- UNSUBSCRIBE, LIST, STATUS, APPEND, and IDLE.
-
-6.3.1. ENABLE Command
-
- Arguments: capability names
-
- Responses: no specific responses for this command
-
- Result: OK - Relevant capabilities enabled
- BAD - No arguments, or syntax error in an argument
-
- Several IMAP extensions allow the server to return unsolicited
- responses specific to these extensions in certain circumstances.
- However, servers cannot send those unsolicited responses (with the
- exception of response codes (see Section 7.1) included in tagged or
- untagged OK/NO/BAD responses, which can always be sent) until they
- know that the clients support such extensions and thus will be able
- to correctly parse and process the extension response data.
-
- The ENABLE command provides an explicit indication from the client
- that it supports particular extensions. It is designed such that the
- client can send a simple constant string with the extensions it
- supports, and the server will enable the shared subset that both
- support.
-
- The ENABLE command takes a list of capability names and requests the
- server to enable the named extensions. Once enabled using ENABLE,
- each extension remains active until the IMAP connection is closed.
- For each argument, the server does the following:
-
- * If the argument is not an extension known to the server, the
- server MUST ignore the argument.
-
- * If the argument is an extension known to the server, and it is not
- specifically permitted to be enabled using ENABLE, the server MUST
- ignore the argument. (Note that knowing about an extension
- doesn't necessarily imply supporting that extension.)
-
- * If the argument is an extension that is supported by the server
- and that needs to be enabled, the server MUST enable the extension
- for the duration of the connection. Note that once an extension
- is enabled, there is no way to disable it.
-
- If the ENABLE command is successful, the server MUST send an untagged
- ENABLED response (Section 7.2.1), which includes all enabled
- extensions as specified above. The ENABLED response is sent even if
- no extensions were enabled.
-
- Clients SHOULD only include extensions that need to be enabled by the
- server. For example, a client can enable IMAP4rev2-specific behavior
- when both IMAP4rev1 and IMAP4rev2 are advertised in the CAPABILITY
- response. Future RFCs may add to this list.
-
- The ENABLE command is only valid in the authenticated state, before
- any mailbox is selected. Clients MUST NOT issue ENABLE once they
- SELECT/EXAMINE a mailbox; however, server implementations don't have
- to check that no mailbox is selected or was previously selected
- during the duration of a connection.
-
- The ENABLE command can be issued multiple times in a session. It is
- additive; that is, "ENABLE a b", followed by "ENABLE c", is the same
- as a single command "ENABLE a b c". When multiple ENABLE commands
- are issued, each corresponding ENABLED response SHOULD only contain
- extensions enabled by the corresponding ENABLE command, i.e., for the
- above example, the ENABLED response to "ENABLE c" should not contain
- "a" or "b".
-
- There are no limitations on pipelining ENABLE. For example, it is
- possible to send ENABLE and then immediately SELECT, or a LOGIN
- immediately followed by ENABLE.
-
- The server MUST NOT change the CAPABILITY list as a result of
- executing ENABLE; that is, a CAPABILITY command issued right after an
- ENABLE command MUST list the same capabilities as a CAPABILITY
- command issued before the ENABLE command. This is demonstrated in
- the following example. Note that below "X-GOOD-IDEA" is a fictitious
- extension capability that can be ENABLED.
-
- C: t1 CAPABILITY
- S: * CAPABILITY IMAP4rev2 ID LITERAL+ X-GOOD-IDEA
- S: t1 OK foo
- C: t2 ENABLE CONDSTORE X-GOOD-IDEA
- S: * ENABLED X-GOOD-IDEA
- S: t2 OK foo
- C: t3 CAPABILITY
- S: * CAPABILITY IMAP4rev2 ID LITERAL+ X-GOOD-IDEA
- S: t3 OK foo again
-
- In the following example, the client enables the Conditional Store
- (CONDSTORE) extension [RFC7162]:
-
- C: a1 ENABLE CONDSTORE
- S: * ENABLED CONDSTORE
- S: a1 OK Conditional Store enabled
-
-6.3.1.1. Note to Designers of Extensions That May Use the ENABLE
- Command
-
- Designers of IMAP extensions are discouraged from creating extensions
- that require ENABLE unless there is no good alternative design.
- Specifically, extensions that cause potentially incompatible behavior
- changes to deployed server responses (and thus benefit from ENABLE)
- have a higher complexity cost than extensions that do not.
-
-6.3.2. SELECT Command
-
- Arguments: mailbox name
-
- Responses: REQUIRED untagged responses: FLAGS, EXISTS, LIST
- REQUIRED OK untagged responses: PERMANENTFLAGS,
- UIDNEXT, UIDVALIDITY
-
- Result: OK - select completed, now in selected state
- NO - select failure, now in authenticated state: no
- such mailbox, can't access mailbox
- BAD - command unknown or arguments invalid
-
- The SELECT command selects a mailbox so that messages in the mailbox
- can be accessed. Before returning an OK to the client, the server
- MUST send the following untagged data to the client. (The order of
- individual responses is not important.) Note that earlier versions
- of this protocol, such as the IMAP4rev1 version specified in
- [RFC2060], only required the FLAGS and EXISTS untagged responses and
- UIDVALIDITY response code. Client implementations that need to
- remain compatible with such older IMAP versions have to implement
- default behavior for missing data, as discussed with the individual
- items.
-
- FLAGS
- Defined flags in the mailbox. See the description of the FLAGS
- response in Section 7.3.5 for more detail.
-
- EXISTS
- The number of messages in the mailbox. See the description of the
- EXISTS response in Section 7.4.1 for more detail.
-
- LIST
- The server MUST return a LIST response with the mailbox name. The
- list of mailbox attributes MUST be accurate. If the server allows
- denormalized UTF-8 mailbox names (see Section 5.1) and the
- supplied mailbox name differs from the normalized version, the
- server MUST return LIST with the OLDNAME extended data item. See
- Section 6.3.9.7 for more details.
-
- OK [PERMANENTFLAGS ()]
- A list of message flags that the client can change permanently.
- If this is missing, the client should assume that all flags can be
- changed permanently.
-
- OK [UIDNEXT ]
- The next unique identifier value. Refer to Section 2.3.1.1 for
- more information.
-
- OK [UIDVALIDITY ]
- The unique identifier validity value. Refer to Section 2.3.1.1
- for more information.
-
- Only one mailbox can be selected at a time in a connection;
- simultaneous access to multiple mailboxes requires multiple
- connections. The SELECT command automatically deselects any
- currently selected mailbox before attempting the new selection.
- Consequently, if a mailbox is selected and a SELECT command that
- fails is attempted, no mailbox is selected. When deselecting a
- selected mailbox, the server MUST return an untagged OK response with
- the "[CLOSED]" response code when the currently selected mailbox is
- closed (see Section 7.1).
-
- If the client is permitted to modify the mailbox, the server SHOULD
- prefix the text of the tagged OK response with the "[READ-WRITE]"
- response code.
-
- If the client is not permitted to modify the mailbox but is permitted
- read access, the mailbox is selected as read-only, and the server
- MUST prefix the text of the tagged OK response to SELECT with the
- "[READ-ONLY]" response code. Read-only access through SELECT differs
- from the EXAMINE command in that certain read-only mailboxes MAY
- permit the change of permanent state on a per-user (as opposed to
- global) basis. Netnews messages marked in a server-based .newsrc
- file are an example of such per-user permanent state that can be
- modified with read-only mailboxes.
-
- Example:
-
- C: A142 SELECT INBOX
- S: * 172 EXISTS
- S: * OK [UIDVALIDITY 3857529045] UIDs valid
- S: * OK [UIDNEXT 4392] Predicted next UID
- S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
- S: * OK [PERMANENTFLAGS (\Deleted \Seen \*)] Limited
- S: * LIST () "/" INBOX
- S: A142 OK [READ-WRITE] SELECT completed
-
- Example:
-
- C: A142 SELECT INBOX
- S: * 172 EXISTS
- S: * OK [UIDVALIDITY 3857529045] UIDs valid
- S: * OK [UIDNEXT 4392] Predicted next UID
- S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
- S: * OK [PERMANENTFLAGS (\Deleted \Seen \*)] Limited
- S: A142 OK [READ-WRITE] SELECT completed
- [...some time later...]
- C: A143 SELECT Drafts
- S: * OK [CLOSED] Previous mailbox is now closed
- S: * 5 EXISTS
- S: * OK [UIDVALIDITY 9877410381] UIDs valid
- S: * OK [UIDNEXT 102] Predicted next UID
- S: * LIST () "/" Drafts
- S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
- S: * OK [PERMANENTFLAGS (\Deleted \Seen \Answered
- \Flagged \Draft \*)] System flags and keywords allowed
- S: A143 OK [READ-WRITE] SELECT completed
-
- Note that IMAP4rev1-compliant servers can also send the untagged
- RECENT response that was deprecated in IMAP4rev2, e.g., "* 0 RECENT".
- Pure IMAP4rev2 clients are advised to ignore the untagged RECENT
- response.
-
-6.3.3. EXAMINE Command
-
- Arguments: mailbox name
-
- Responses: REQUIRED untagged responses: FLAGS, EXISTS, LIST
- REQUIRED OK untagged responses: PERMANENTFLAGS,
- UIDNEXT, UIDVALIDITY
-
- Result: OK - examine completed, now in selected state
- NO - examine failure, now in authenticated state: no
- such mailbox, can't access mailbox
- BAD - command unknown or arguments invalid
-
- The EXAMINE command is identical to SELECT and returns the same
- output; however, the selected mailbox is identified as read-only. No
- changes to the permanent state of the mailbox, including per-user
- state, are permitted.
-
- The text of the tagged OK response to the EXAMINE command MUST begin
- with the "[READ-ONLY]" response code.
-
- Example:
-
- C: A932 EXAMINE blurdybloop
- S: * 17 EXISTS
- S: * OK [UIDVALIDITY 3857529045] UIDs valid
- S: * OK [UIDNEXT 4392] Predicted next UID
- S: * LIST () "/" blurdybloop
- S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
- S: * OK [PERMANENTFLAGS ()] No permanent flags permitted
- S: A932 OK [READ-ONLY] EXAMINE completed
-
-6.3.4. CREATE Command
-
- Arguments: mailbox name
-
- Responses: OPTIONAL untagged response: LIST
-
- Result: OK - create completed
- NO - create failure: can't create mailbox with that
- name
- BAD - command unknown or arguments invalid
-
- The CREATE command creates a mailbox with the given name. An OK
- response is returned only if a new mailbox with that name has been
- created. It is an error to attempt to create INBOX or a mailbox with
- a name that refers to an extant mailbox. Any error in creation will
- return a tagged NO response. If a client attempts to create a UTF-8
- mailbox name that is not a valid Net-Unicode name, the server MUST
- reject the creation or convert the name to Net-Unicode prior to
- creating the mailbox. If the server decides to convert (normalize)
- the name, it SHOULD return an untagged LIST with an OLDNAME extended
- data item, with the OLDNAME value being the supplied mailbox name and
- the name parameter being the normalized mailbox name. (See
- Section 6.3.9.7 for more details.)
-
- Mailboxes created in one IMAP session MAY be announced to other IMAP
- sessions using an unsolicited LIST response. If the server
- automatically subscribes a mailbox when it is created, then the
- unsolicited LIST response for each affected subscribed mailbox name
- MUST include the \Subscribed attribute.
-
- If the mailbox name is suffixed with the server's hierarchy separator
- character (as returned from the server by a LIST command), this is a
- declaration that the client intends to create mailbox names under
- this name in the hierarchy. Server implementations that do not
- require this declaration MUST ignore the declaration. In any case,
- the name created is without the trailing hierarchy delimiter.
-
- If the server's hierarchy separator character appears elsewhere in
- the name, the server SHOULD create any superior hierarchical names
- that are needed for the CREATE command to be successfully completed.
- In other words, an attempt to create "foo/bar/zap" on a server in
- which "/" is the hierarchy separator character SHOULD create foo/ and
- foo/bar/ if they do not already exist.
-
- If a new mailbox is created with the same name as a mailbox that was
- deleted, its unique identifiers MUST be greater than any unique
- identifiers used in the previous incarnation of the mailbox unless
- the new incarnation has a different unique identifier validity value.
- See the description of the UID command in Section 6.4.9 for more
- detail.
-
- Example:
-
- C: A003 CREATE owatagusiam/
- S: A003 OK CREATE completed
- C: A004 CREATE owatagusiam/blurdybloop
- S: A004 OK CREATE completed
- C: A005 CREATE NonNormalized
- S: * LIST () "/" "Normalized" ("OLDNAME" ("NonNormalized"))
- S: A005 OK CREATE completed
-
- (In the last example, imagine that "NonNormalized" is a non-NFC
- normalized Unicode mailbox name and that "Normalized" is its NFC
- normalized version.)
-
- | Note: The interpretation of this example depends on whether "/"
- | was returned as the hierarchy separator from LIST. If "/" is
- | the hierarchy separator, a new level of hierarchy named
- | "owatagusiam" with a member called "blurdybloop" is created.
- | Otherwise, two mailboxes at the same hierarchy level are
- | created.
-
-6.3.5. DELETE Command
-
- Arguments: mailbox name
-
- Responses: OPTIONAL untagged response: LIST
-
- Result: OK - delete completed
- NO - delete failure: can't delete mailbox with that
- name
- BAD - command unknown or arguments invalid
-
- The DELETE command permanently removes the mailbox with the given
- name. A tagged OK response is returned only if the mailbox has been
- deleted. It is an error to attempt to delete INBOX or a mailbox name
- that does not exist.
-
- The DELETE command MUST NOT remove inferior hierarchical names. For
- example, if a mailbox "foo" has an inferior "foo.bar" (assuming "."
- is the hierarchy delimiter character), removing "foo" MUST NOT remove
- "foo.bar". It is an error to attempt to delete a name that has
- inferior hierarchical names and also has the \Noselect mailbox name
- attribute (see the description of the LIST response (Section 7.3.1)
- for more details).
-
- It is permitted to delete a name that has inferior hierarchical names
- and does not have the \Noselect mailbox name attribute. If the
- server implementation does not permit deleting the name while
- inferior hierarchical names exist, then it SHOULD disallow the DELETE
- command by returning a tagged NO response. The NO response SHOULD
- include the HASCHILDREN response code. Alternatively, the server MAY
- allow the DELETE command, but it sets the \Noselect mailbox name
- attribute for that name.
-
- If the server returns an OK response, all messages in that mailbox
- are removed by the DELETE command.
-
- The value of the highest-used unique identifier of the deleted
- mailbox MUST be preserved so that a new mailbox created with the same
- name will not reuse the identifiers of the former incarnation, unless
- the new incarnation has a different unique identifier validity value.
- See the description of the UID command in Section 6.4.9 for more
- detail.
-
- If the server decides to convert (normalize) the mailbox name, it
- SHOULD return an untagged LIST with the "\NonExistent" attribute and
- OLDNAME extended data item, with the OLDNAME value being the supplied
- mailbox name and the name parameter being the normalized mailbox
- name. (See Section 6.3.9.7 for more details.)
-
- Mailboxes deleted in one IMAP session MAY be announced to other IMAP
- sessions using an unsolicited LIST response, containing the
- "\NonExistent" attribute.
-
- Example:
-
- C: A682 LIST "" *
- S: * LIST () "/" blurdybloop
- S: * LIST (\Noselect) "/" foo
- S: * LIST () "/" foo/bar
- S: A682 OK LIST completed
- C: A683 DELETE blurdybloop
- S: A683 OK DELETE completed
- C: A684 DELETE foo
- S: A684 NO Name "foo" has inferior hierarchical names
- C: A685 DELETE foo/bar
- S: A685 OK DELETE Completed
- C: A686 LIST "" *
- S: * LIST (\Noselect) "/" foo
- S: A686 OK LIST completed
- C: A687 DELETE foo
- S: A687 OK DELETE Completed
-
- Example:
-
- C: A82 LIST "" *
- S: * LIST () "." blurdybloop
- S: * LIST () "." foo
- S: * LIST () "." foo.bar
- S: A82 OK LIST completed
- C: A83 DELETE blurdybloop
- S: A83 OK DELETE completed
- C: A84 DELETE foo
- S: A84 OK DELETE Completed
- C: A85 LIST "" *
- S: * LIST () "." foo.bar
- S: A85 OK LIST completed
- C: A86 LIST "" %
- S: * LIST (\Noselect) "." foo
- S: A86 OK LIST completed
-
-6.3.6. RENAME Command
-
- Arguments: existing mailbox name
-
- new mailbox name
-
- Responses: OPTIONAL untagged response: LIST
-
- Result: OK - rename completed
- NO - rename failure: can't rename mailbox with that
- name, can't rename to mailbox with that name
- BAD - command unknown or arguments invalid
-
- The RENAME command changes the name of a mailbox. A tagged OK
- response is returned only if the mailbox has been renamed. It is an
- error to attempt to rename from a mailbox name that does not exist or
- to a mailbox name that already exists. Any error in renaming will
- return a tagged NO response.
-
- If the name has inferior hierarchical names, then the inferior
- hierarchical names MUST also be renamed. For example, a rename of
- "foo" to "zap" will rename "foo/bar" (assuming "/" is the hierarchy
- delimiter character) to "zap/bar".
-
- If the server's hierarchy separator character appears in the new
- mailbox name, the server SHOULD create any superior hierarchical
- names that are needed for the RENAME command to complete
- successfully. In other words, an attempt to rename "foo/bar/zap" to
- "baz/rag/zowie" on a server in which "/" is the hierarchy separator
- character in the corresponding namespace SHOULD create "baz/" and
- "baz/rag/" if they do not already exist.
-
- The value of the highest-used unique identifier of the old mailbox
- name MUST be preserved so that a new mailbox created with the same
- name will not reuse the identifiers of the former incarnation, unless
- the new incarnation has a different unique identifier validity value.
- See the description of the UID command in Section 6.4.9 for more
- detail.
-
- Renaming INBOX is permitted and does not result in a tagged BAD
- response, and it has special behavior: It moves all messages in INBOX
- to a new mailbox with the given name, leaving INBOX empty. If the
- server implementation supports inferior hierarchical names of INBOX,
- these are unaffected by a rename of INBOX. (Note that some servers
- disallow renaming INBOX by returning a tagged NO response, so clients
- need to be able to handle the failure of such RENAME commands.)
-
- If the server allows creation of mailboxes with names that are not
- valid Net-Unicode names, the server normalizes both the existing
- mailbox name parameter and the new mailbox name parameter. If the
- normalized version of any of these 2 parameters differs from the
- corresponding supplied version, the server SHOULD return an untagged
- LIST response with an OLDNAME extended data item, with the OLDNAME
- value being the supplied existing mailbox name and the name parameter
- being the normalized new mailbox name (see Section 6.3.9.7). This
- would allow the client to correlate the supplied name with the
- normalized name.
-
- Mailboxes renamed in one IMAP session MAY be announced to other IMAP
- sessions using an unsolicited LIST response with an OLDNAME extended
- data item.
-
- In both of the above cases, if the server automatically subscribes a
- mailbox when it is renamed, then the unsolicited LIST response for
- each affected subscribed mailbox name MUST include the \Subscribed
- attribute. No unsolicited LIST responses need to be sent for child
- mailboxes. When INBOX is successfully renamed, it is assumed that a
- new INBOX is created. No unsolicited LIST responses need to be sent
- for INBOX in this case.
-
- Examples:
-
- C: A682 LIST "" *
- S: * LIST () "/" blurdybloop
- S: * LIST (\Noselect) "/" foo
- S: * LIST () "/" foo/bar
- S: A682 OK LIST completed
- C: A683 RENAME blurdybloop sarasoop
- S: A683 OK RENAME completed
- C: A684 RENAME foo zowie
- S: A684 OK RENAME Completed
- C: A685 LIST "" *
- S: * LIST () "/" sarasoop
- S: * LIST (\Noselect) "/" zowie
- S: * LIST () "/" zowie/bar
- S: A685 OK LIST completed
-
- C: Z432 LIST "" *
- S: * LIST () "." INBOX
- S: * LIST () "." INBOX.bar
- S: Z432 OK LIST completed
- C: Z433 RENAME INBOX old-mail
- S: Z433 OK RENAME completed
- C: Z434 LIST "" *
- S: * LIST () "." INBOX
- S: * LIST () "." INBOX.bar
- S: * LIST () "." old-mail
- S: Z434 OK LIST completed
-
- Note that renaming a mailbox doesn't update subscription information
- on the original name. To keep subscription information in sync, the
- following sequence of commands can be used:
-
- C: 1001 RENAME X Y
- C: 1002 SUBSCRIBE Y
- C: 1003 UNSUBSCRIBE X
-
- Note that the above sequence of commands doesn't account for updating
- the subscription for any child mailboxes of mailbox X.
-
-6.3.7. SUBSCRIBE Command
-
- Arguments: mailbox
-
- Responses: no specific responses for this command
-
- Result: OK - subscribe completed
- NO - subscribe failure: can't subscribe to that name
- BAD - command unknown or arguments invalid
-
- The SUBSCRIBE command adds the specified mailbox name to the server's
- set of "active" or "subscribed" mailboxes as returned by the LIST
- (SUBSCRIBED) command. This command returns a tagged OK response if
- the subscription is successful or if the mailbox is already
- subscribed.
-
- A server MAY validate the mailbox argument to SUBSCRIBE to verify
- that it exists. However, it SHOULD NOT unilaterally remove an
- existing mailbox name from the subscription list even if a mailbox by
- that name no longer exists.
-
- | Note: This requirement is because a server site can choose to
- | routinely remove a mailbox with a well-known name (e.g.,
- | "system-alerts") after its contents expire, with the intention
- | of recreating it when new contents are appropriate.
-
- Example:
-
- C: A002 SUBSCRIBE #news.comp.mail.mime
- S: A002 OK SUBSCRIBE completed
-
-6.3.8. UNSUBSCRIBE Command
-
- Arguments: mailbox name
-
- Responses: no specific responses for this command
-
- Result: OK - unsubscribe completed
- NO - unsubscribe failure: can't unsubscribe that name
- BAD - command unknown or arguments invalid
-
- The UNSUBSCRIBE command removes the specified mailbox name from the
- server's set of "active" or "subscribed" mailboxes as returned by the
- LIST (SUBSCRIBED) command. This command returns a tagged OK response
- if the unsubscription is successful or if the mailbox is not
- subscribed.
-
- Example:
-
- C: A002 UNSUBSCRIBE #news.comp.mail.mime
- S: A002 OK UNSUBSCRIBE completed
-
-6.3.9. LIST Command
-
- Arguments (basic):
- reference name
- mailbox name with possible wildcards
-
- Arguments (extended):
- selection options (OPTIONAL)
- reference name
- mailbox patterns
- return options (OPTIONAL)
-
- Responses: untagged responses: LIST
-
- Result: OK - list completed
- NO - list failure: can't list that reference or
- mailbox name
- BAD - command unknown or arguments invalid
-
- The LIST command returns a subset of mailbox names from the complete
- set of all mailbox names available to the client. Zero or more
- untagged LIST responses are returned, containing the name attributes,
- hierarchy delimiter, name, and possible extension information; see
- the description of the LIST response (Section 7.3.1) for more detail.
-
- The LIST command SHOULD return its data quickly, without undue delay.
- For example, it should not go to excess trouble to calculate the
- \Marked or \Unmarked status or perform other processing; if each name
- requires 1 second of processing, then a list of 1200 names would take
- 20 minutes!
-
- The extended LIST command, originally introduced in [RFC5258],
- provides capabilities beyond that of the original IMAP LIST command.
- The extended syntax is being used if one or more of the following
- conditions is true:
-
- 1. the first word after the command name begins with a parenthesis
- ("LIST selection options");
-
- 2. the second word after the command name begins with a parenthesis;
- and
-
- 3. the LIST command has more than 2 parameters ("LIST return
- options").
-
- An empty ("" string) reference name argument indicates that the
- mailbox name is interpreted as by SELECT. The returned mailbox names
- MUST match the supplied mailbox name pattern(s). A non-empty
- reference name argument is the name of a mailbox or a level of
- mailbox hierarchy, and it indicates the context in which the mailbox
- name is interpreted. Clients SHOULD use the empty reference
- argument.
-
- In the basic syntax only, an empty ("" string) mailbox name argument
- is a special request to return the hierarchy delimiter and the root
- name of the name given in the reference. The value returned as the
- root MAY be the empty string if the reference is non-rooted or is an
- empty string. In all cases, a hierarchy delimiter (or NIL if there
- is no hierarchy) is returned. This permits a client to get the
- hierarchy delimiter (or find out that the mailbox names are flat)
- even when no mailboxes by that name currently exist.
-
- In the extended syntax, any mailbox name arguments that are empty
- strings are ignored. There is no special meaning for empty mailbox
- names when the extended syntax is used.
-
- The reference and mailbox name arguments are interpreted into a
- canonical form that represents an unambiguous left-to-right
- hierarchy. The returned mailbox names will be in the interpreted
- form, which we call a "canonical LIST pattern": the canonical pattern
- constructed internally by the server from the reference and mailbox
- name arguments.
-
- Note: The interpretation of the reference argument is
- implementation defined. It depends on whether the server
- implementation has a concept of the "current working directory"
- and leading "break out characters", which override the current
- working directory.
-
- For example, on a server that exports a UNIX or NT file system,
- the reference argument contains the current working directory, and
- the mailbox name argument contains the name as interpreted in the
- current working directory.
-
- If a server implementation has no concept of break out characters,
- the canonical form is normally the reference name appended with
- the mailbox name. Note that if the server implements the
- namespace convention (Section 5.1.2.1), "#" is a break out
- character and must be treated as such.
-
- If the reference argument is not a level of mailbox hierarchy
- (that is, it is a \NoInferiors name), and/or the reference
- argument does not end with the hierarchy delimiter, it is
- interpreted as implementation dependent. For example, a reference
- of "foo/bar" and mailbox name of "rag/baz" could be interpreted as
- "foo/bar/rag/baz", "foo/barrag/baz", or "foo/rag/baz". A client
- SHOULD NOT use such a reference argument except at the explicit
- request of the user. A hierarchical browser MUST NOT make any
- assumptions about server interpretation of the reference unless
- the reference is a level of mailbox hierarchy AND ends with the
- hierarchy delimiter.
-
- Any part of the reference argument that is included in the
- interpreted form SHOULD prefix the interpreted form. It SHOULD also
- be in the same form as the reference name argument. This rule
- permits the client to determine if the returned mailbox name is in
- the context of the reference argument or if something about the
- mailbox argument overrode the reference argument. Without this rule,
- the client would have to have knowledge of the server's naming
- semantics including what characters are "breakouts" that override a
- naming context.
-
- Here are some examples of how references and mailbox names might be
- interpreted on a UNIX-based server:
-
- +==============+==============+===================+
- | Reference | Mailbox Name | Interpretation |
- +==============+==============+===================+
- | ~smith/Mail/ | foo.* | ~smith/Mail/foo.* |
- +--------------+--------------+-------------------+
- | archive/ | % | archive/% |
- +--------------+--------------+-------------------+
- | #news. | comp.mail.* | #news.comp.mail.* |
- +--------------+--------------+-------------------+
- | ~smith/Mail/ | /usr/doc/foo | /usr/doc/foo |
- +--------------+--------------+-------------------+
- | archive/ | ~fred/Mail/* | ~fred/Mail/* |
- +--------------+--------------+-------------------+
-
- Table 1
-
- The first three examples above demonstrate interpretations in the
- context of the reference argument. Note that "~smith/Mail" SHOULD
- NOT be transformed into something like "/u2/users/smith/Mail", or it
- would be impossible for the client to determine that the
- interpretation was in the context of the reference.
-
- The character "*" is a wildcard and matches zero or more characters
- at this position. The character "%" is similar to "*", but it does
- not match a hierarchy delimiter. If the "%" wildcard is the last
- character of a mailbox name argument, matching levels of hierarchy
- are also returned. If these levels of hierarchy are not also
- selectable mailboxes, they are returned with the \Noselect mailbox
- name attribute (see the description of the LIST response
- (Section 7.3.1) for more details).
-
- Any syntactically valid pattern that is not accepted by a server for
- any reason MUST be silently ignored, i.e., it results in no LIST
- responses, and the LIST command still returns a tagged OK response.
-
- Selection options tell the server to limit the mailbox names that are
- selected by the LIST operation. If selection options are used, the
- mailboxes returned are those that match both the list of canonical
- LIST patterns and the selection options. Unless a particular
- selection option provides special rules, the selection options are
- cumulative: a mailbox that matches the mailbox patterns is selected
- only if it also matches all of the selection options. (An example of
- a selection option with special rules is the RECURSIVEMATCH option.)
-
- Return options control what information is returned for each matched
- mailbox. Return options MUST NOT cause the server to report
- information about additional mailbox names other than those that
- match the canonical LIST patterns and selection options. If no
- return options are specified, the client is only expecting
- information about mailbox attributes. The server MAY return other
- information about the matched mailboxes, and clients MUST be able to
- handle that situation.
-
- Initial selection options and return options are defined in the
- following subsections, and new ones will also be defined in
- extensions. Initial options defined in this document MUST be
- supported. Each non-initial option will be enabled by a capability
- string (one capability may enable multiple options), and a client
- MUST NOT send an option for which the server has not advertised
- support. A server MUST respond to options it does not recognize with
- a BAD response. The client SHOULD NOT specify any option more than
- once; however, if the client does this, the server MUST act as if it
- received the option only once. The order in which options are
- specified by the client is not significant.
-
- In general, each selection option except RECURSIVEMATCH will have a
- corresponding return option with the same name. The REMOTE selection
- option is an anomaly in this regard and does not have a corresponding
- return option. That is because it expands, rather than restricts,
- the set of mailboxes that are returned. Future extensions to this
- specification should keep this parallelism in mind and define a pair
- of corresponding selection and return options.
-
- Server implementations are permitted to "hide" otherwise accessible
- mailboxes from the wildcard characters, by preventing certain
- characters or names from matching a wildcard in certain situations.
- For example, a UNIX-based server might restrict the interpretation of
- "*" so that an initial "/" character does not match.
-
- The special name INBOX is included in the output from LIST, if INBOX
- is supported by this server for this user and if the uppercase string
- "INBOX" matches the interpreted reference and mailbox name arguments
- with wildcards as described above. The criteria for omitting INBOX
- is whether SELECT INBOX will return a failure; it is not relevant
- whether the user's real INBOX resides on this or some other server.
-
-6.3.9.1. LIST Selection Options
-
- The selection options defined in this specification are as follows:
-
- SUBSCRIBED
- Causes the LIST command to list subscribed names rather than the
- existing mailboxes. This will often be a subset of the actual
- mailboxes. It's also possible for this list to contain the names
- of mailboxes that don't exist. In any case, the list MUST include
- exactly those mailbox names that match the canonical list pattern
- and are subscribed to.
-
- This option defines a mailbox attribute, "\Subscribed", that
- indicates that a mailbox name is subscribed to. The "\Subscribed"
- attribute MUST be supported and MUST be accurately computed when
- the SUBSCRIBED selection option is specified.
-
- Note that the SUBSCRIBED selection option implies the SUBSCRIBED
- return option (see below).
-
- REMOTE
- Causes the LIST command to show remote mailboxes as well as local
- ones, as described in [RFC2193]. This option is intended to
- replace the RLIST command and, in conjunction with the SUBSCRIBED
- selection option, the RLSUB command. Servers that don't support
- the concept of remote mailboxes can ignore this option.
-
- This option defines a mailbox attribute, "\Remote", that indicates
- that a mailbox is a remote mailbox. The "\Remote" attribute MUST
- be accurately computed when the REMOTE option is specified.
-
- The REMOTE selection option has no interaction with other options.
- Its effect is to tell the server to apply the other options, if
- any, to remote mailboxes, in addition to local ones. In
- particular, it has no interaction with RECURSIVEMATCH (see below).
- A request for (REMOTE RECURSIVEMATCH) is invalid, because a
- request for (RECURSIVEMATCH) is also invalid. A request for
- (REMOTE RECURSIVEMATCH SUBSCRIBED) is asking for all subscribed
- mailboxes, both local and remote.
-
- RECURSIVEMATCH
- Forces the server to return information about parent mailboxes
- that don't match other selection options but have some
- submailboxes that do. Information about children is returned in
- the CHILDINFO extended data item, as described in Section 6.3.9.6.
-
- Note 1: In order for a parent mailbox to be returned, it still
- has to match the canonical LIST pattern.
-
- Note 2: When returning the CHILDINFO extended data item, it
- doesn't matter whether or not the submailbox matches the
- canonical LIST pattern. See also Example 9 in Section 6.3.9.8.
-
- The RECURSIVEMATCH option MUST NOT occur as the only selection
- option (or only with REMOTE), as it only makes sense when other
- selection options are also used. The server MUST return a BAD
- tagged response in such case.
-
- Note that even if the RECURSIVEMATCH option is specified, the
- client MUST still be able to handle cases when a CHILDINFO
- extended data item is returned and there are no submailboxes that
- meet the selection criteria of the subsequent LIST command, as
- they can be deleted/renamed after the LIST response was sent but
- before the client had a chance to access them.
-
-6.3.9.2. LIST Return Options
-
- The return options defined in this specification are as follows:
-
- SUBSCRIBED
- Causes the LIST command to return subscription state for all
- matching mailbox names. The "\Subscribed" attribute MUST be
- supported and MUST be accurately computed when the SUBSCRIBED
- return option is specified. Furthermore, all other mailbox
- attributes MUST be accurately computed (this differs from the
- behavior of the obsolete LSUB command from [RFC3501]). Note that
- the above requirements don't override the requirement for the LIST
- command to return results quickly (see Section 6.3.9), i.e.,
- server implementations need to compute results quickly and
- accurately. For example, server implementors might need to create
- quick access indices.
-
- CHILDREN
- Requests mailbox child information as originally proposed in
- [RFC3348]. See Section 6.3.9.5, below, for details.
-
- STATUS
- Requests STATUS response for each matching mailbox.
-
- This option takes STATUS data items as parameters. For each
- selectable mailbox matching the list pattern and selection
- options, the server MUST return an untagged LIST response followed
- by an untagged STATUS response containing the information
- requested in the STATUS return option, except for some cases
- described below.
-
- If an attempted STATUS for a listed mailbox fails because the
- mailbox can't be selected (e.g., if the "l" Access Control List
- (ACL) right [RFC4314] is granted to the mailbox and the "r" right
- is not granted, or is due to a race condition between LIST and
- STATUS changing the mailbox to \NoSelect), the STATUS response
- MUST NOT be returned, and the LIST response MUST include the
- \NoSelect attribute. This means the server may have to buffer the
- LIST reply until it has successfully looked up the necessary
- STATUS information.
-
- If the server runs into unexpected problems while trying to look
- up the STATUS information, it MAY drop the corresponding STATUS
- reply. In such a situation, the LIST command would still return a
- tagged OK reply.
-
- See the note in the discussion of the STATUS command in
- Section 6.3.11 for information about obtaining status on the
- currently selected mailbox.
-
-6.3.9.3. General Principles for Returning LIST Responses
-
- This section outlines several principles that can be used by server
- implementations of this document to decide whether a LIST response
- should be returned, as well as how many responses and what kind of
- information they may contain.
-
- 1. At most, one LIST response should be returned for each mailbox
- name that matches the canonical LIST pattern. Server
- implementors must not assume that clients will be able to
- assemble mailbox attributes and other information returned in
- multiple LIST responses.
-
- 2. There are only two reasons for including a matching mailbox name
- in the responses to the LIST command (note that the server is
- allowed to return unsolicited responses at any time, and such
- responses are not governed by this rule):
-
- A. The mailbox name also satisfies the selection criteria.
-
- B. The mailbox name doesn't satisfy the selection criteria, but
- it has at least one descendant mailbox name that satisfies
- the selection criteria and that doesn't match the canonical
- LIST pattern.
-
- For more information on this case, see the CHILDINFO extended
- data item described in Section 6.3.9.6. Note that the
- CHILDINFO extended data item can only be returned when the
- RECURSIVEMATCH selection option is specified.
-
- 3. Attributes returned in the same LIST response are treated
- additively. For example, the following response
-
- S: * LIST (\Subscribed \NonExistent) "/" "Fruit/Peach"
-
- means that the "Fruit/Peach" mailbox doesn't exist, but it is
- subscribed.
-
-6.3.9.4. Additional LIST-Related Requirements on Clients
-
- All clients MUST treat a LIST attribute with a stronger meaning as
- implying any attribute that can be inferred from it. (See
- Section 7.3.1 for the list of currently defined attributes.) For
- example, the client must treat the presence of the \NoInferiors
- attribute as if the \HasNoChildren attribute was also sent by the
- server.
-
- The following table summarizes inference rules.
-
- +====================+===================+
- | returned attribute | implied attribute |
- +====================+===================+
- | \NoInferiors | \HasNoChildren |
- +--------------------+-------------------+
- | \NonExistent | \NoSelect |
- +--------------------+-------------------+
-
- Table 2
-
-6.3.9.5. The CHILDREN Return Option
-
- The CHILDREN return option is simply an indication that the client
- wants information about whether or not mailboxes contain child
- mailboxes; a server MAY provide it even if the option is not
- specified.
-
- Many IMAP clients present the user with a hierarchical view of the
- mailboxes that a user has access to. Rather than initially
- presenting the entire mailbox hierarchy to the user, it is often
- preferable to show the user a collapsed outline list of the mailbox
- hierarchy (particularly if there is a large number of mailboxes).
- The user can then expand the collapsed outline hierarchy as needed.
- It is common to include a visual clue (such as a ''+'') within the
- collapsed hierarchy to indicate that there are child mailboxes under
- a particular mailbox. When the visual clue is clicked, the hierarchy
- list is expanded to show the child mailboxes. The CHILDREN return
- option provides a mechanism for a client to efficiently determine
- whether a particular mailbox has children, without issuing a LIST ""
- * or a LIST "" % for each mailbox name. The CHILDREN return option
- defines two new attributes that MUST be returned within a LIST
- response: \HasChildren and \HasNoChildren. Although these attributes
- MAY be returned in response to any LIST command, the CHILDREN return
- option is provided to indicate that the client particularly wants
- this information. If the CHILDREN return option is present, the
- server MUST return these attributes even if their computation is
- expensive.
-
- \HasChildren
- The presence of this attribute indicates that the mailbox has
- child mailboxes. A server SHOULD NOT set this attribute if
- there are child mailboxes and the user does not have permission
- to access any of them. In this case, \HasNoChildren SHOULD be
- used. In many cases, however, a server may not be able to
- efficiently compute whether a user has access to any child
- mailbox. Note that even though the \HasChildren attribute for a
- mailbox must be correct at the time of processing the mailbox, a
- client must be prepared to deal with a situation when a mailbox
- is marked with the \HasChildren attribute, but no child mailbox
- appears in the response to the LIST command. This might happen,
- for example, due to child mailboxes being deleted or made
- inaccessible to the user (using access control) by another
- client before the server is able to list them.
-
- \HasNoChildren
- The presence of this attribute indicates that the mailbox has NO
- child mailboxes that are accessible to the currently
- authenticated user.
-
- It is an error for the server to return both a \HasChildren and a
- \HasNoChildren attribute in the same LIST response.
-
- Note: the \HasNoChildren attribute should not be confused with the
- \NoInferiors attribute, which indicates that no child mailboxes exist
- now and none can be created in the future.
-
-6.3.9.6. CHILDINFO Extended Data Item
-
- The CHILDINFO extended data item MUST NOT be returned unless the
- client has specified the RECURSIVEMATCH selection option.
-
- The CHILDINFO extended data item in a LIST response describes the
- selection criteria that has caused it to be returned and indicates
- that the mailbox has at least one descendant mailbox that matches the
- selection criteria.
-
- Note: Some servers allow for mailboxes to exist without requiring
- their parent to exist. For example, the mailbox "Customers/ABC" can
- exist while the mailbox "Customers" does not. As the CHILDINFO
- extended data item is not allowed if the RECURSIVEMATCH selection
- option is not specified, such servers SHOULD use the "\NonExistent
- \HasChildren" attribute pair to signal to the client that there is a
- descendant mailbox that matches the selection criteria. See Example
- 11 in Section 6.3.9.8.
-
- The returned selection criteria allows the client to distinguish a
- solicited response from an unsolicited one, as well as to distinguish
- among solicited responses caused by multiple pipelined LIST commands
- that specify different criteria.
-
- Servers SHOULD only return a non-matching mailbox name along with
- CHILDINFO if at least one matching child is not also being returned.
- That is, servers SHOULD suppress redundant CHILDINFO responses.
-
- Examples 8 and 10 in Section 6.3.9.8 demonstrate the difference
- between the present CHILDINFO extended data item and the
- "\HasChildren" attribute.
-
- The following table summarizes interaction between the "\NonExistent"
- attribute and CHILDINFO (the first column indicates whether the
- parent mailbox exists):
-
- +========+===========+====================+=====================+
- | Exists | Meets the | Has a child that | Returned IMAP4rev2/ |
- | | selection | meets the | LIST-EXTENDED |
- | | criteria | selection criteria | attributes and |
- | | | | CHILDINFO |
- +========+===========+====================+=====================+
- | no | no | no | no LIST response |
- | | | | returned |
- +--------+-----------+--------------------+---------------------+
- | yes | no | no | no LIST response |
- | | | | returned |
- +--------+-----------+--------------------+---------------------+
- | no | yes | no | (\NonExistent |
- | | | | ) |
- +--------+-----------+--------------------+---------------------+
- | yes | yes | no | () |
- +--------+-----------+--------------------+---------------------+
- | no | no | yes | (\NonExistent) + |
- | | | | CHILDINFO |
- +--------+-----------+--------------------+---------------------+
- | yes | no | yes | () + CHILDINFO |
- +--------+-----------+--------------------+---------------------+
- | no | yes | yes | (\NonExistent |
- | | | | ) + CHILDINFO |
- +--------+-----------+--------------------+---------------------+
- | yes | yes | yes | () + |
- | | | | CHILDINFO |
- +--------+-----------+--------------------+---------------------+
-
- Table 3
-
- where is one or more attributes that correspond to the
- selection criteria; for example, for the SUBSCRIBED option, the
- is \Subscribed.
-
-6.3.9.7. OLDNAME Extended Data Item
-
- The OLDNAME extended data item is included when a mailbox name is
- created (with the CREATE command), renamed (with the RENAME command),
- or deleted (with the DELETE command). (When a mailbox is deleted,
- the "\NonExistent" attribute is also included.) IMAP extensions can
- specify other conditions when the OLDNAME extended data item should
- be included.
-
- If the server allows denormalized mailbox names (see Section 5.1) in
- SELECT/EXAMINE, CREATE, RENAME, or DELETE, it SHOULD return an
- unsolicited LIST response that includes the OLDNAME extended data
- item, whenever the supplied mailbox name differs from the resulting
- normalized mailbox name. From the client point of view, this is
- indistinguishable from another user renaming or deleting the mailbox,
- as specified in the previous paragraph.
-
- A deleted mailbox can be announced as follows:
-
- S: * LIST (\NonExistent) "." "INBOX.DeletedMailbox"
-
- Example of a renamed mailbox:
-
- S: * LIST () "/" "NewMailbox" ("OLDNAME" ("OldMailbox"))
-
-6.3.9.8. LIST Command Examples
-
- This example shows some uses of the basic LIST command:
-
- Example:
-
- C: A101 LIST "" ""
- S: * LIST (\Noselect) "/" ""
- S: A101 OK LIST Completed
- C: A102 LIST #news.comp.mail.misc ""
- S: * LIST (\Noselect) "." #news.
- S: A102 OK LIST Completed
- C: A103 LIST /usr/staff/jones ""
- S: * LIST (\Noselect) "/" /
- S: A103 OK LIST Completed
- C: A202 LIST ~/Mail/ %
- S: * LIST (\Noselect) "/" ~/Mail/foo
- S: * LIST () "/" ~/Mail/meetings
- S: A202 OK LIST completed
-
- Extended examples:
-
- 1: The first example shows the complete local hierarchy that will
- be used for the other examples.
-
- C: A01 LIST "" "*"
- S: * LIST (\Marked \NoInferiors) "/" "inbox"
- S: * LIST () "/" "Fruit"
- S: * LIST () "/" "Fruit/Apple"
- S: * LIST () "/" "Fruit/Banana"
- S: * LIST () "/" "Tofu"
- S: * LIST () "/" "Vegetable"
- S: * LIST () "/" "Vegetable/Broccoli"
- S: * LIST () "/" "Vegetable/Corn"
- S: A01 OK done
-
- 2: In the next example, we will see the subscribed mailboxes. This
- is similar to, but not equivalent with, the now deprecated (see [RFC3501] for more details on the LSUB command).
- Note that the mailbox called "Fruit/Peach" is subscribed to, but
- it does not actually exist (perhaps it was deleted while still
- subscribed). The "Fruit" mailbox is not subscribed to, but it
- has two subscribed children. The "Vegetable" mailbox is
- subscribed and has two children; one of them is subscribed as
- well.
-
- C: A02 LIST (SUBSCRIBED) "" "*"
- S: * LIST (\Marked \NoInferiors \Subscribed) "/" "inbox"
- S: * LIST (\Subscribed) "/" "Fruit/Banana"
- S: * LIST (\Subscribed \NonExistent) "/" "Fruit/Peach"
- S: * LIST (\Subscribed) "/" "Vegetable"
- S: * LIST (\Subscribed) "/" "Vegetable/Broccoli"
- S: A02 OK done
-
- 3: The next example shows the use of the CHILDREN option. The
- client, without having to list the second level of hierarchy,
- now knows which of the top-level mailboxes have submailboxes
- (children) and which do not. Note that it's not necessary for
- the server to return the \HasNoChildren attribute for the inbox,
- because the \NoInferiors attribute already implies that and has
- a stronger meaning.
-
- C: A03 LIST () "" "%" RETURN (CHILDREN)
- S: * LIST (\Marked \NoInferiors) "/" "inbox"
- S: * LIST (\HasChildren) "/" "Fruit"
- S: * LIST (\HasNoChildren) "/" "Tofu"
- S: * LIST (\HasChildren) "/" "Vegetable"
- S: A03 OK done
-
- 4: In this example, we see more mailboxes that reside on another
- server. This is similar to the command .
-
- C: A04 LIST (REMOTE) "" "%" RETURN (CHILDREN)
- S: * LIST (\Marked \NoInferiors) "/" "inbox"
- S: * LIST (\HasChildren) "/" "Fruit"
- S: * LIST (\HasNoChildren) "/" "Tofu"
- S: * LIST (\HasChildren) "/" "Vegetable"
- S: * LIST (\Remote \HasNoChildren) "/" "Bread"
- S: * LIST (\HasChildren \Remote) "/" "Meat"
- S: A04 OK done
-
- 5: The following example also requests the server to include
- mailboxes that reside on another server. The server returns
- information about all mailboxes that are subscribed. This is
- similar to the command (see [RFC2193] for more
- details on RLSUB). We also see the use of two selection
- options.
-
- C: A05 LIST (REMOTE SUBSCRIBED) "" "*"
- S: * LIST (\Marked \NoInferiors \Subscribed) "/" "inbox"
- S: * LIST (\Subscribed) "/" "Fruit/Banana"
- S: * LIST (\Subscribed \NonExistent) "/" "Fruit/Peach"
- S: * LIST (\Subscribed) "/" "Vegetable"
- S: * LIST (\Subscribed) "/" "Vegetable/Broccoli"
- S: * LIST (\Remote \Subscribed) "/" "Bread"
- S: A05 OK done
-
- 6: The following example requests the server to include mailboxes
- that reside on another server. The server is asked to return
- subscription information for all returned mailboxes. This is
- different from the example above.
-
- Note that the output of this command is not a superset of the
- output in the previous example, as it doesn't include a LIST
- response for the non-existent "Fruit/Peach".
-
- C: A06 LIST (REMOTE) "" "*" RETURN (SUBSCRIBED)
- S: * LIST (\Marked \NoInferiors \Subscribed) "/" "inbox"
- S: * LIST () "/" "Fruit"
- S: * LIST () "/" "Fruit/Apple"
- S: * LIST (\Subscribed) "/" "Fruit/Banana"
- S: * LIST () "/" "Tofu"
- S: * LIST (\Subscribed) "/" "Vegetable"
- S: * LIST (\Subscribed) "/" "Vegetable/Broccoli"
- S: * LIST () "/" "Vegetable/Corn"
- S: * LIST (\Remote \Subscribed) "/" "Bread"
- S: * LIST (\Remote) "/" "Meat"
- S: A06 OK done
-
- 7: The following example demonstrates the difference between the
- \HasChildren attribute and the CHILDINFO extended data item.
-
- Let's assume there is the following hierarchy:
-
- C: C01 LIST "" "*"
- S: * LIST (\Marked \NoInferiors) "/" "inbox"
- S: * LIST () "/" "Foo"
- S: * LIST () "/" "Foo/Bar"
- S: * LIST () "/" "Foo/Baz"
- S: * LIST () "/" "Moo"
- S: C01 OK done
-
- If the client asks RETURN (CHILDREN), it will get this:
-
- C: CA3 LIST "" "%" RETURN (CHILDREN)
- S: * LIST (\Marked \NoInferiors) "/" "inbox"
- S: * LIST (\HasChildren) "/" "Foo"
- S: * LIST (\HasNoChildren) "/" "Moo"
- S: CA3 OK done
-
- A) Let's also assume that the mailbox "Foo/Baz" is the only
- subscribed mailbox. Then we get this result:
-
- C: C02 LIST (SUBSCRIBED) "" "*"
- S: * LIST (\Subscribed) "/" "Foo/Baz"
- S: C02 OK done
-
- Now, if the client issues , the
- server will return no mailboxes (as the mailboxes "Moo",
- "Foo", and "Inbox" are NOT subscribed). However, if the
- client issues this:
-
- C: C04 LIST (SUBSCRIBED RECURSIVEMATCH) "" "%"
- S: * LIST () "/" "Foo" ("CHILDINFO" ("SUBSCRIBED"))
- S: C04 OK done
-
- (that is, the mailbox "Foo" is not subscribed, but it has a
- child that is), then A1 or A2 occurs.
-
- A1) If the mailbox "Foo" had also been subscribed, the last
- command would return this:
-
- C: C04 LIST (SUBSCRIBED RECURSIVEMATCH) "" "%"
- S: * LIST (\Subscribed) "/" "Foo" ("CHILDINFO"
- ("SUBSCRIBED"))
- S: C04 OK done
-
- or even this:
-
- C: C04 LIST (SUBSCRIBED RECURSIVEMATCH) "" "%"
- S: * LIST (\Subscribed \HasChildren) "/" "Foo"
- ("CHILDINFO" ("SUBSCRIBED"))
- S: C04 OK done
-
- A2) If we assume instead that the mailbox "Foo" is not part
- of the original hierarchy and is not subscribed, the
- last command will give this result:
-
- C: C04 LIST (SUBSCRIBED RECURSIVEMATCH) "" "%"
- S: * LIST (\NonExistent) "/" "Foo" ("CHILDINFO"
- ("SUBSCRIBED"))
- S: C04 OK done
-
- B) Now, let's assume that no mailbox is subscribed. In this
- case, the command
- will return no responses, as there are no subscribed
- children (even though "Foo" has children).
-
- C) And finally, suppose that only the mailboxes "Foo" and "Moo"
- are subscribed. In that case, we see this result:
-
- C: C04 LIST (SUBSCRIBED RECURSIVEMATCH) "" "%" RETURN
- (CHILDREN)
- S: * LIST (\HasChildren \Subscribed) "/" "Foo"
- S: * LIST (\HasNoChildren \Subscribed) "/" "Moo"
- S: C04 OK done
-
- (which means that the mailbox "Foo" has children, but none
- of them is subscribed).
-
- 8: The following example demonstrates that the CHILDINFO extended
- data item is returned whether or not child mailboxes match the
- canonical LIST pattern.
-
- Let's assume there is the following hierarchy:
-
- C: D01 LIST "" "*"
- S: * LIST (\Marked \NoInferiors) "/" "inbox"
- S: * LIST () "/" "foo2"
- S: * LIST () "/" "foo2/bar1"
- S: * LIST () "/" "foo2/bar2"
- S: * LIST () "/" "baz2"
- S: * LIST () "/" "baz2/bar2"
- S: * LIST () "/" "baz2/bar22"
- S: * LIST () "/" "baz2/bar222"
- S: * LIST () "/" "eps2"
- S: * LIST () "/" "eps2/mamba"
- S: * LIST () "/" "qux2/bar2"
- S: D01 OK done
-
- And that the following mailboxes are subscribed:
-
- C: D02 LIST (SUBSCRIBED) "" "*"
- S: * LIST (\Subscribed) "/" "foo2/bar1"
- S: * LIST (\Subscribed) "/" "foo2/bar2"
- S: * LIST (\Subscribed) "/" "baz2/bar2"
- S: * LIST (\Subscribed) "/" "baz2/bar22"
- S: * LIST (\Subscribed) "/" "baz2/bar222"
- S: * LIST (\Subscribed) "/" "eps2"
- S: * LIST (\Subscribed) "/" "eps2/mamba"
- S: * LIST (\Subscribed) "/" "qux2/bar2"
- S: D02 OK done
-
- The client issues the following command first:
-
- C: D03 LIST (RECURSIVEMATCH SUBSCRIBED) "" "*2"
- S: * LIST () "/" "foo2" ("CHILDINFO" ("SUBSCRIBED"))
- S: * LIST (\Subscribed) "/" "foo2/bar2"
- S: * LIST (\Subscribed) "/" "baz2/bar2"
- S: * LIST (\Subscribed) "/" "baz2/bar22"
- S: * LIST (\Subscribed) "/" "baz2/bar222"
- S: * LIST (\Subscribed) "/" "eps2" ("CHILDINFO" ("SUBSCRIBED"))
- S: * LIST (\Subscribed) "/" "qux2/bar2"
- S: D03 OK done
-
- and the server may also include the following (but this would
- violate a restriction in Section 6.3.9.6, because CHILDINFO is
- redundant):
-
- S: * LIST () "/" "baz2" ("CHILDINFO" ("SUBSCRIBED"))
- S: * LIST (\NonExistent) "/" "qux2" ("CHILDINFO" ("SUBSCRIBED"))
-
- The CHILDINFO extended data item is returned for mailboxes
- "foo2", "baz2", and "eps2" because all of them have subscribed
- children, even though for the mailbox "foo2", only one of the
- two subscribed children matches the pattern; for the mailbox
- "baz2", all of the subscribed children match the pattern; and
- for the mailbox "eps2", none of the subscribed children match
- the pattern.
-
- Note that if the client issues the following:
-
- C: D03 LIST (RECURSIVEMATCH SUBSCRIBED) "" "*"
- S: * LIST () "/" "foo2" ("CHILDINFO" ("SUBSCRIBED"))
- S: * LIST (\Subscribed) "/" "foo2/bar1"
- S: * LIST (\Subscribed) "/" "foo2/bar2"
- S: * LIST () "/" "baz2" ("CHILDINFO" ("SUBSCRIBED"))
- S: * LIST (\Subscribed) "/" "baz2/bar2"
- S: * LIST (\Subscribed) "/" "baz2/bar22"
- S: * LIST (\Subscribed) "/" "baz2/bar222"
- S: * LIST (\Subscribed) "/" "eps2" ("CHILDINFO" ("SUBSCRIBED"))
- S: * LIST (\Subscribed) "/" "eps2/mamba"
- S: * LIST (\Subscribed) "/" "qux2/bar2"
- S: D03 OK done
-
- the LIST responses for mailboxes "foo2", "baz2", and "eps2"
- still have the CHILDINFO extended data item, even though this
- information is redundant and the client can determine it by
- itself.
-
- 9: The following example shows usage of an extended syntax for the
- mailbox pattern. It also demonstrates that the presence of the
- CHILDINFO extended data item doesn't necessarily imply
- \HasChildren.
-
- C: a1 LIST "" ("foo")
- S: * LIST () "/" foo
- S: a1 OK done
-
- C: a2 LIST (SUBSCRIBED) "" "foo/*"
- S: * LIST (\Subscribed \NonExistent) "/" foo/bar
- S: a2 OK done
-
- C: a3 LIST (SUBSCRIBED RECURSIVEMATCH) "" foo RETURN (CHILDREN)
- S: * LIST (\HasNoChildren) "/" foo ("CHILDINFO" ("SUBSCRIBED"))
- S: a3 OK done
-
- 10: The following example shows how a server that supports missing
- mailbox hierarchy elements can signal to a client that didn't
- specify the RECURSIVEMATCH selection option that there is a
- child mailbox that matches the selection criteria.
-
- C: a1 LIST (REMOTE) "" *
- S: * LIST () "/" music/rock
- S: * LIST (\Remote) "/" also/jazz
- S: a1 OK done
-
- C: a2 LIST () "" %
- S: * LIST (\NonExistent \HasChildren) "/" music
- S: a2 OK done
-
- C: a3 LIST (REMOTE) "" %
- S: * LIST (\NonExistent \HasChildren) "/" music
- S: * LIST (\NonExistent \HasChildren) "/" also
- S: a3 OK done
-
- C: a3.1 LIST "" (% music/rock)
- S: * LIST () "/" music/rock
- S: a3.1 OK done
-
- Because "music/rock" is the only mailbox under "music", there's
- no need for the server to also return "music". However, clients
- must handle both cases.
-
- 11: The following examples show use of the STATUS return option.
-
- C: A01 LIST "" % RETURN (STATUS (MESSAGES UNSEEN))
- S: * LIST () "." "INBOX"
- S: * STATUS "INBOX" (MESSAGES 17 UNSEEN 16)
- S: * LIST () "." "foo"
- S: * STATUS "foo" (MESSAGES 30 UNSEEN 29)
- S: * LIST (\NoSelect) "." "bar"
- S: A01 OK List completed.
-
- The "bar" mailbox isn't selectable, so it has no STATUS reply.
-
- C: A02 LIST (SUBSCRIBED RECURSIVEMATCH) "" % RETURN (STATUS
- (MESSAGES))
- S: * LIST (\Subscribed) "." "INBOX"
- S: * STATUS "INBOX" (MESSAGES 17)
- S: * LIST () "." "foo" (CHILDINFO ("SUBSCRIBED"))
- S: A02 OK List completed.
-
- The LIST reply for "foo" is returned because it has matching
- children, but no STATUS reply is returned because "foo" itself
- doesn't match the selection criteria.
-
-6.3.10. NAMESPACE Command
-
- Arguments: none
-
- Responses: REQUIRED untagged responses: NAMESPACE
-
- Result: OK - command completed
- NO - Can't complete the command
- BAD - arguments invalid
-
- The NAMESPACE command causes a single untagged NAMESPACE response to
- be returned. The untagged NAMESPACE response contains the prefix and
- hierarchy delimiter to the server's Personal Namespace(s), Other
- Users' Namespace(s), and Shared Namespace(s) that the server wishes
- to expose. The response will contain a NIL for any namespace class
- that is not available. The namespace-response-extensions ABNF non-
- terminal is defined for extensibility and MAY be included in the
- NAMESPACE response.
-
- Example 1:
-
- In this example, a server supports a single Personal Namespace. No
- leading prefix is used on personal mailboxes, and "/" is the
- hierarchy delimiter.
-
- C: A001 NAMESPACE
- S: * NAMESPACE (("" "/")) NIL NIL
- S: A001 OK NAMESPACE command completed
-
- Example 2:
-
- A user logged on anonymously to a server. No personal mailboxes are
- associated with the anonymous user, and the user does not have access
- to the Other Users' Namespace. No prefix is required to access
- shared mailboxes, and the hierarchy delimiter is "."
-
- C: A001 NAMESPACE
- S: * NAMESPACE NIL NIL (("" "."))
- S: A001 OK NAMESPACE command completed
-
- Example 3:
-
- A server that contains a Personal Namespace and a single Shared
- Namespace.
-
- C: A001 NAMESPACE
- S: * NAMESPACE (("" "/")) NIL (("Public Folders/" "/"))
- S: A001 OK NAMESPACE command completed
-
- Example 4:
-
- A server that contains a Personal Namespace, Other Users' Namespace,
- and multiple Shared Namespaces. Note that the hierarchy delimiter
- used within each namespace can be different.
-
- C: A001 NAMESPACE
- S: * NAMESPACE (("" "/")) (("~" "/")) (("#shared/" "/")
- ("#public/" "/")("#ftp/" "/")("#news." "."))
- S: A001 OK NAMESPACE command completed
-
- The prefix string allows a client to do things such as automatically
- create personal mailboxes or LIST all available mailboxes within a
- namespace.
-
- Example 5:
-
- A server that supports only the Personal Namespace, with a leading
- prefix of INBOX to personal mailboxes and a hierarchy delimiter of
- ".".
-
- C: A001 NAMESPACE
- S: * NAMESPACE (("INBOX." ".")) NIL NIL
- S: A001 OK NAMESPACE command completed
-
- Automatically create a mailbox to store sent items.
-
- C: A002 CREATE "INBOX.Sent Mail"
- S: A002 OK CREATE command completed
-
- Although a server will typically support only a single Personal
- Namespace, and a single Other User's Namespace, circumstances exist
- where there MAY be multiples of these, and a client MUST be prepared
- for them. If a client is configured such that it is required to
- create a certain mailbox, there can be circumstances where it is
- unclear which Personal Namespaces it should create the mailbox in.
- In these situations, a client SHOULD let the user select which
- namespaces to create the mailbox in, or just use the first Personal
- Namespace.
-
- Example 6:
-
- In this example, a server supports two Personal Namespaces. In
- addition to the regular Personal Namespace, the user has an
- additional Personal Namespace that allows access to mailboxes in an
- MH format mailstore.
-
- The client is configured to save a copy of all mail sent by the user
- into a mailbox with the \Sent attribute (see Section 7.3.1).
- Furthermore, after a message is deleted from a mailbox, the client is
- configured to move that message to a mailbox with the \Trash
- attribute. The server signals with the \NonExistent mailbox
- attribute that the corresponding mailboxes don't exist yet and that
- it is possible to create them. Once created, they could be used for
- \Sent or \Trash purposes, and the server will no longer include the
- \NonExistent mailbox attribute for them.
-
- Note that this example demonstrates how some extension parameters can
- be passed to further describe the #mh namespace. See the fictitious
- "X-PARAM" extension parameter.
-
- C: A001 NAMESPACE
- S: * NAMESPACE (("" "/")("#mh/" "/" "X-PARAM"
- ("FLAG1" "FLAG2"))) NIL NIL
- S: A001 OK NAMESPACE command completed
-
- C: A002 LIST (SPECIAL-USE) "" "*"
- S: * LIST (\NonExistent \Archive) "/" Archives
- S: * LIST (\NonExistent \Drafts) "/" Drafts
- S: * LIST (\NonExistent \Junk) "/" Junk
- S: * LIST (\NonExistent \Sent) "/" "Sent Mail"
- S: * LIST (\NonExistent \Trash) "/" "Deleted Items"
- S: A002 OK LIST Completed
-
- C: A003 LIST (SPECIAL-USE) "#mh/" "*"
- S: * LIST (\NonExistent \Archive) "/" "#mh/Archives"
- S: * LIST (\NonExistent \Drafts) "/" "#mh/Drafts"
- S: * LIST (\NonExistent \Junk) "/" "#mh/Junk"
- S: * LIST (\NonExistent \Sent) "/" "#mh/Sent Mail"
- S: * LIST (\NonExistent \Trash) "/" "#mh/Deleted Items"
- S: A003 OK LIST Completed
-
- It is desired to keep only one copy of sent mail. It is unclear
- which Personal Namespace the client should use to create the 'Sent
- Mail' mailbox. The user is prompted to select a namespace, and only
- one 'Sent Mail' mailbox is created.
-
- C: A004 CREATE "Sent Mail"
- S: A004 OK CREATE command completed
-
- The client is designed so that it keeps two 'Deleted Items'
- mailboxes, one for each namespace.
-
- C: A005 CREATE "Delete Items"
- S: A005 OK CREATE command completed
-
- C: A006 CREATE "#mh/Deleted Items"
- S: A006 OK CREATE command completed
-
- The next level of hierarchy following the Other Users' Namespace
- prefix SHOULD consist of , where is a user name
- as per the LOGIN or AUTHENTICATE command.
-
- A client can construct a LIST command by appending a "%" to the Other
- Users' Namespace prefix to discover the Personal Namespaces of other
- users that are available to the currently authenticated user.
-
- In response to such a LIST command, a server SHOULD NOT return user
- names that have not granted access to their personal mailboxes to the
- user in question.
-
- A server MAY return a LIST response containing only the names of
- users that have explicitly granted access to the user in question.
-
- Alternatively, a server MAY return NO to such a LIST command,
- requiring that a user name be included with the Other Users'
- Namespace prefix before listing any other user's mailboxes.
-
- Example 7:
-
- A server that supports providing a list of other user's mailboxes
- that are accessible to the currently logged on user.
-
- C: A001 NAMESPACE
- S: * NAMESPACE (("" "/")) (("Other Users/" "/")) NIL
- S: A001 OK NAMESPACE command completed
-
- C: A002 LIST "" "Other Users/%"
- S: * LIST () "/" "Other Users/Mike"
- S: * LIST () "/" "Other Users/Karen"
- S: * LIST () "/" "Other Users/Matthew"
- S: * LIST () "/" "Other Users/Tesa"
- S: A002 OK LIST command completed
-
- Example 8:
-
- A server that does not support providing a list of other user's
- mailboxes that are accessible to the currently logged on user. The
- mailboxes are listable if the client includes the name of the other
- user with the Other Users' Namespace prefix.
-
- C: A001 NAMESPACE
- S: * NAMESPACE (("" "/")) (("#Users/" "/")) NIL
- S: A001 OK NAMESPACE command completed
-
- In this example, the currently logged on user has access to the
- Personal Namespace of user Mike, but the server chose to suppress
- this information in the LIST response. However, by appending the
- user name Mike (received through user input) to the Other Users'
- Namespace prefix, the client is able to get a listing of the personal
- mailboxes of user Mike.
-
- C: A002 LIST "" "#Users/%"
- S: A002 NO The requested item could not be found.
-
- C: A003 LIST "" "#Users/Mike/%"
- S: * LIST () "/" "#Users/Mike/INBOX"
- S: * LIST () "/" "#Users/Mike/Foo"
- S: A003 OK LIST command completed.
-
- A prefix string might not contain a hierarchy delimiter, because in
- some cases, it is not needed as part of the prefix.
-
- Example 9:
-
- A server that allows access to the Other Users' Namespace by
- prefixing the others' mailboxes with a '~' followed by ,
- where is a user name as per the LOGIN or AUTHENTICATE
- command.
-
- C: A001 NAMESPACE
- S: * NAMESPACE (("" "/")) (("~" "/")) NIL
- S: A001 OK NAMESPACE command completed
-
- List the mailboxes for user mark
-
- C: A002 LIST "" "~mark/%"
- S: * LIST () "/" "~mark/INBOX"
- S: * LIST () "/" "~mark/foo"
- S: A002 OK LIST command completed
-
-6.3.11. STATUS Command
-
- Arguments: mailbox name
-
- status data item names
-
- Responses: REQUIRED untagged responses: STATUS
-
- Result: OK - status completed
- NO - status failure: no status for that name
- BAD - command unknown or arguments invalid
-
- The STATUS command requests the status of the indicated mailbox. It
- does not change the currently selected mailbox, nor does it affect
- the state of any messages in the queried mailbox.
-
- The STATUS command provides an alternative to opening a second
- IMAP4rev2 connection and doing an EXAMINE command on a mailbox to
- query that mailbox's status without deselecting the current mailbox
- in the first IMAP4rev2 connection.
-
- Unlike the LIST command, the STATUS command is not guaranteed to be
- fast in its response. Under certain circumstances, it can be quite
- slow. In some implementations, the server is obliged to open the
- mailbox as "read-only" internally to obtain certain status
- information. Also unlike the LIST command, the STATUS command does
- not accept wildcards.
-
- Note: The STATUS command is intended to access the status of
- mailboxes other than the currently selected mailbox. Because the
- STATUS command can cause the mailbox to be opened internally, and
- because this information is available by other means on the
- selected mailbox, the STATUS command SHOULD NOT be used on the
- currently selected mailbox. However, servers MUST be able to
- execute the STATUS command on the selected mailbox. (This might
- also implicitly happen when the STATUS return option is used in a
- LIST command.)
-
- The STATUS command MUST NOT be used as a "check for new messages
- in the selected mailbox" operation (refer to Sections 7 and 7.4.1
- for more information about the proper method for new message
- checking).
-
- STATUS SIZE (see below) can take a significant amount of time,
- depending upon server implementation. Clients should use STATUS
- SIZE cautiously.
-
- The currently defined status data items that can be requested are:
-
- MESSAGES
- The number of messages in the mailbox.
-
- UIDNEXT
- The next unique identifier value of the mailbox. Refer to
- Section 2.3.1.1 for more information.
-
- UIDVALIDITY
- The unique identifier validity value of the mailbox. Refer to
- Section 2.3.1.1 for more information.
-
- UNSEEN
- The number of messages that do not have the \Seen flag set.
-
- DELETED
- The number of messages that have the \Deleted flag set.
-
- SIZE
- The total size of the mailbox in octets. This is not strictly
- required to be an exact value, but it MUST be equal to or greater
- than the sum of the values of the RFC822.SIZE FETCH message data
- items (see Section 6.4.5) of all messages in the mailbox.
-
- Example:
-
- C: A042 STATUS blurdybloop (UIDNEXT MESSAGES)
- S: * STATUS blurdybloop (MESSAGES 231 UIDNEXT 44292)
- S: A042 OK STATUS completed
-
-6.3.12. APPEND Command
-
- Arguments: mailbox name
-
- OPTIONAL flag parenthesized list
-
- OPTIONAL date/time string
-
- message literal
-
- Responses: OPTIONAL untagged response: LIST
-
- Result: OK - append completed
- NO - append error: can't append to that mailbox, error
- in flags or date/time or message text
- BAD - command unknown or arguments invalid
-
- The APPEND command appends the literal argument as a new message to
- the end of the specified destination mailbox. This argument SHOULD
- be in the format of an [RFC5322] or [I18N-HDRS] message. 8-bit
- characters are permitted in the message. A server implementation
- that is unable to preserve 8-bit data properly MUST be able to
- reversibly convert 8-bit APPEND data to 7 bits using a [MIME-IMB]
- content transfer encoding.
-
- Note: There may be exceptions, such as draft messages, in which
- required [RFC5322] header fields are omitted in the message
- literal argument to APPEND. The full implications of doing so
- must be understood and carefully weighed.
-
- If a flag parenthesized list is specified, the flags SHOULD be set in
- the resulting message; otherwise, the flag list of the resulting
- message is set to "empty" by default.
-
- If a date-time is specified, the internal date SHOULD be set in the
- resulting message; otherwise, the internal date of the resulting
- message is set to the current date and time by default.
-
- If the append is unsuccessful for any reason, the mailbox MUST be
- restored to its state before the APPEND attempt (other than possibly
- keeping the changed mailbox's UIDNEXT value); no partial appending is
- permitted.
-
- If the destination mailbox does not exist, a server MUST return an
- error and MUST NOT automatically create the mailbox. Unless it is
- certain that the destination mailbox cannot be created, the server
- MUST send the response code "[TRYCREATE]" as the prefix of the text
- of the tagged NO response. This gives a hint to the client that it
- can attempt a CREATE command and retry the APPEND if the CREATE is
- successful.
-
- On successful completion of an APPEND, the server returns an
- APPENDUID response code (see Section 7.1), unless otherwise specified
- below.
-
- In the case of a mailbox that has permissions set so that the client
- can APPEND to the mailbox, but not SELECT or EXAMINE it, the server
- MUST NOT send an APPENDUID response code as it would disclose
- information about the mailbox.
-
- In the case of a mailbox that has UIDNOTSTICKY status (see
- Section 7.1), the server MAY omit the APPENDUID response code as it
- is not meaningful.
-
- If the mailbox is currently selected, normal new message actions
- SHOULD occur. Specifically, the server SHOULD notify the client
- immediately via an untagged EXISTS response. If the server does not
- do so, the client MAY issue a NOOP command after one or more APPEND
- commands.
-
- If the server decides to convert (normalize) the mailbox name, it
- SHOULD return an untagged LIST with an OLDNAME extended data item,
- with the OLDNAME value being the supplied mailbox name and the name
- parameter being the normalized mailbox name. (See Section 6.3.9.7
- for more details.)
-
- Example:
-
- C: A003 APPEND saved-messages (\Seen) {326}
- S: + Ready for literal data
- C: Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
- C: From: Fred Foobar
- C: Subject: afternoon meeting
- C: To: mooch@owatagu.siam.edu.example
- C: Message-Id:
- C: MIME-Version: 1.0
- C: Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
- C:
- C: Hello Joe, do you think we can meet at 3:30 tomorrow?
- C:
- S: A003 OK APPEND completed
-
- Example:
-
- C: A003 APPEND saved-messages (\Seen) {297+}
- C: Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
- C: From: Fred Foobar
- C: Subject: afternoon meeting
- C: To: mooch@example.com
- C: Message-Id:
- C: MIME-Version: 1.0
- C: Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
- C:
- C: Hello Joe, do you think we can meet at 3:30 tomorrow?
- C:
- S: A003 OK [APPENDUID 38505 3955] APPEND completed
- C: A004 COPY 2:4 meeting
- S: A004 OK [COPYUID 38505 304,319:320 3956:3958] Done
- C: A005 UID COPY 305:310 meeting
- S: A005 OK No matching messages, so nothing copied
- C: A006 COPY 2 funny
- S: A006 OK Done
- C: A007 SELECT funny
- S: * 1 EXISTS
- S: * OK [UIDVALIDITY 3857529045] Validity session-only
- S: * OK [UIDNEXT 2] Predicted next UID
- S: * NO [UIDNOTSTICKY] Non-persistent UIDs
- S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
- S: * OK [PERMANENTFLAGS (\Deleted \Seen)] Limited
- S: * LIST () "." funny
- S: A007 OK [READ-WRITE] SELECT completed
-
- In this example, A003 and A004 demonstrate successful appending and
- copying to a mailbox that returns the UIDs assigned to the messages.
- A005 is an example in which no messages were copied; this is because
- in A003, we see that message 2 had UID 304, and message 3 had UID
- 319; therefore, UIDs 305 through 310 do not exist (refer to
- Section 2.3.1.1 for further explanation). A006 is an example of a
- message being copied that did not return a COPYUID; and, as expected,
- A007 shows that the mail store containing that mailbox does not
- support persistent UIDs.
-
- | Note: The APPEND command is not used for message delivery,
- | because it does not provide a mechanism to transfer [SMTP]
- | envelope information.
-
-6.3.13. IDLE Command
-
- Arguments: none
-
- Responses: continuation data will be requested; the client sends
- the continuation data "DONE" to end the command
-
- Result: OK - IDLE completed after client sent "DONE"
- NO - failure: the server will not allow the IDLE
- command at this time
- BAD - command unknown or arguments invalid
-
- Without the IDLE command, a client would need to poll the server for
- changes to the selected mailbox (new mail, deletions, and flag
- changes). It's often more desirable to have the server transmit
- updates to the client in real time. This allows a user to see new
- mail immediately. The IDLE command allows a client to tell the
- server that it's ready to accept such real-time updates.
-
- The IDLE command is sent from the client to the server when the
- client is ready to accept unsolicited update messages. The server
- requests a response to the IDLE command using the continuation ("+")
- response. The IDLE command remains active until the client responds
- to the continuation, and as long as an IDLE command is active, the
- server is now free to send untagged EXISTS, EXPUNGE, FETCH, and other
- responses at any time. If the server chooses to send unsolicited
- FETCH responses, they MUST include a UID FETCH item.
-
- The IDLE command is terminated by the receipt of a "DONE"
- continuation from the client; such response satisfies the server's
- continuation request. At that point, the server MAY send any
- remaining queued untagged responses and then MUST immediately send
- the tagged response to the IDLE command and prepare to process other
- commands. As for other commands, the processing of any new command
- may cause the sending of unsolicited untagged responses, subject to
- the ambiguity limitations. The client MUST NOT send a command while
- the server is waiting for the DONE, since the server will not be able
- to distinguish a command from a continuation.
-
- The server MAY consider a client inactive if it has an IDLE command
- running, and if such a server has an inactivity timeout, it MAY log
- the client off implicitly at the end of its timeout period. Because
- of that, clients using IDLE are advised to terminate IDLE and reissue
- it at least every 29 minutes to avoid being logged off. This still
- allows a client to receive immediate mailbox updates even though it
- need only "poll" at half hour intervals.
-
- Example:
-
- C: A001 SELECT INBOX
- S: * FLAGS (\Deleted \Seen \Flagged)
- S: * OK [PERMANENTFLAGS (\Deleted \Seen \Flagged)] Limited
- S: * 3 EXISTS
- S: * OK [UIDVALIDITY 1]
- S: * OK [UIDNEXT 1]
- S: * LIST () "/" INBOX
- S: A001 OK [READ-WRITE] SELECT completed
- C: A002 IDLE
- S: + idling
- ...time passes; new mail arrives...
- S: * 4 EXISTS
- C: DONE
- S: A002 OK IDLE terminated
- ...another client expunges message 2 now...
- C: A003 FETCH 4 ALL
- S: * 4 FETCH (...)
- S: A003 OK FETCH completed
- C: A004 IDLE
- S: * 2 EXPUNGE
- S: * 3 EXISTS
- S: + idling
- ...time passes; another client expunges message 3...
- S: * 3 EXPUNGE
- S: * 2 EXISTS
- ...time passes; new mail arrives...
- S: * 3 EXISTS
- C: DONE
- S: A004 OK IDLE terminated
- C: A005 FETCH 3 ALL
- S: * 3 FETCH (...)
- S: A005 OK FETCH completed
- C: A006 IDLE
-
-6.4. Client Commands - Selected State
-
- In the selected state, commands that manipulate messages in a mailbox
- are permitted.
-
- In addition to the universal commands (CAPABILITY, NOOP, and LOGOUT),
- and the authenticated state commands (SELECT, EXAMINE, NAMESPACE,
- CREATE, DELETE, RENAME, SUBSCRIBE, UNSUBSCRIBE, LIST, STATUS, and
- APPEND), the following commands are valid in the selected state:
- CLOSE, UNSELECT, EXPUNGE, SEARCH, FETCH, STORE, COPY, MOVE, and UID.
-
-6.4.1. CLOSE Command
-
- Arguments: none
-
- Responses: no specific responses for this command
-
- Result: OK - close completed, now in authenticated state
- BAD - command unknown or arguments invalid
-
- The CLOSE command permanently removes all messages that have the
- \Deleted flag set from the currently selected mailbox, and it returns
- to the authenticated state from the selected state. No untagged
- EXPUNGE responses are sent.
-
- No messages are removed, and no error is given, if the mailbox is
- selected by an EXAMINE command or is otherwise selected as read-only.
-
- Even if a mailbox is selected, a SELECT, EXAMINE, or LOGOUT command
- MAY be issued without previously issuing a CLOSE command. The
- SELECT, EXAMINE, and LOGOUT commands implicitly close the currently
- selected mailbox without doing an expunge. However, when many
- messages are deleted, a CLOSE-LOGOUT or CLOSE-SELECT sequence is
- considerably faster than an EXPUNGE-LOGOUT or EXPUNGE-SELECT because
- no untagged EXPUNGE responses (which the client would probably
- ignore) are sent.
-
- Example:
-
- C: A341 CLOSE
- S: A341 OK CLOSE completed
-
-6.4.2. UNSELECT Command
-
- Arguments: none
-
- Responses: no specific responses for this command
-
- Result: OK - unselect completed, now in authenticated state
- BAD - no mailbox selected, or argument supplied but
- none permitted
-
- The UNSELECT command frees a session's resources associated with the
- selected mailbox and returns the server to the authenticated state.
- This command performs the same actions as CLOSE, except that no
- messages are permanently removed from the currently selected mailbox.
-
- Example:
-
- C: A342 UNSELECT
- S: A342 OK Unselect completed
-
-6.4.3. EXPUNGE Command
-
- Arguments: none
-
- Responses: untagged responses: EXPUNGE
-
- Result: OK - expunge completed
- NO - expunge failure: can't expunge (e.g., permission
- denied)
- BAD - command unknown or arguments invalid
-
- The EXPUNGE command permanently removes all messages that have the
- \Deleted flag set from the currently selected mailbox. Before
- returning an OK to the client, an untagged EXPUNGE response is sent
- for each message that is removed.
-
- Example:
-
- C: A202 EXPUNGE
- S: * 3 EXPUNGE
- S: * 3 EXPUNGE
- S: * 5 EXPUNGE
- S: * 8 EXPUNGE
- S: A202 OK EXPUNGE completed
-
- Note: In this example, messages 3, 4, 7, and 11 had the \Deleted flag
- set. See the description of the EXPUNGE response (Section 7.5.1) for
- further explanation.
-
-6.4.4. SEARCH Command
-
- Arguments: OPTIONAL result specifier
-
- OPTIONAL [CHARSET] specification
-
- searching criteria (one or more)
-
- Responses: OPTIONAL untagged response: ESEARCH
-
- Result: OK - search completed
- NO - search error: can't search that [CHARSET] or
- criteria
- BAD - command unknown or arguments invalid
-
- The SEARCH command searches the mailbox for messages that match the
- given searching criteria.
-
- The SEARCH command may contain result options. Result options
- control what kind of information is returned about messages matching
- the search criteria in an untagged ESEARCH response. If no result
- option is specified or empty list of options is specified as "()",
- ALL is assumed (see below). The order of individual options is
- arbitrary. Individual options may contain parameters enclosed in
- parentheses. (However, if an option has a mandatory parameter, which
- can always be represented as a number or a sequence-set, the option
- parameter does not need the enclosing parentheses. See "Formal
- Syntax" (Section 9) for more details.) If an option has parameters,
- they consist of atoms and/or strings and/or lists in a specific
- order. Any options not defined by extensions that the server
- supports MUST be rejected with a BAD response.
-
- Note that IMAP4rev1 used SEARCH responses [RFC3501] instead of
- ESEARCH responses. Clients that support only IMAP4rev2 MUST ignore
- SEARCH responses.
-
- This document specifies the following result options:
-
- MIN
- Return the lowest message number/UID that satisfies the SEARCH
- criteria.
-
- If the SEARCH results in no matches, the server MUST NOT include
- the MIN result option in the ESEARCH response; however, it still
- MUST send the ESEARCH response.
-
- MAX
- Return the highest message number/UID that satisfies the SEARCH
- criteria.
-
- If the SEARCH results in no matches, the server MUST NOT include
- the MAX result option in the ESEARCH response; however, it still
- MUST send the ESEARCH response.
-
- ALL
- Return all message numbers/UIDs that satisfy the SEARCH criteria
- using the sequence-set syntax. Note that the client MUST NOT
- assume that messages/UIDs will be listed in any particular order.
-
- If the SEARCH results in no matches, the server MUST NOT include
- the ALL result option in the ESEARCH response; however, it still
- MUST send the ESEARCH response.
-
- COUNT
- Return the number of messages that satisfy the SEARCH criteria.
- This result option MUST always be included in the ESEARCH
- response.
-
- SAVE
- This option tells the server to remember the result of the SEARCH
- or UID SEARCH command (as well as any command based on SEARCH,
- e.g., SORT and THREAD [RFC5256]) and store it in an internal
- variable that we will reference as the "search result variable".
- The client can use the "$" marker to reference the content of this
- internal variable. The "$" marker can be used instead of message
- sequence or UID sequence in order to indicate that the server
- should substitute it with the list of messages from the search
- result variable. Thus, the client can use the result of the
- latest remembered SEARCH command as a parameter to another
- command. See Section 6.4.4.1 for details on how the value of the
- search result variable is determined, how it is affected by other
- commands executed, and how the SAVE return option interacts with
- other return options.
-
- In absence of any other SEARCH result option, the SAVE result
- option also suppresses any ESEARCH response that would have been
- otherwise returned by the SEARCH command.
-
- Note: future extensions to this document can allow servers to return
- multiple ESEARCH responses for a single extended SEARCH command.
- However, all options specified above MUST result in a single ESEARCH
- response if used by themselves or in combination. This guarantee
- simplifies processing in IMAP4rev2 clients. Future SEARCH extensions
- that relax this restriction will have to describe how results from
- multiple ESEARCH responses are to be combined.
-
- Searching criteria consist of one or more search keys.
-
- When multiple keys are specified, the result is the intersection (AND
- function) of all the messages that match those keys. For example,
- the criteria DELETED FROM "SMITH" SINCE 1-Feb-1994 refers to all
- deleted messages from Smith with INTERNALDATE greater than February
- 1, 1994. A search key can also be a parenthesized list of one or
- more search keys (e.g., for use with the OR and NOT keys).
-
- Server implementations MAY exclude [MIME-IMB] body parts with
- terminal content media types other than TEXT and MESSAGE from
- consideration in SEARCH matching.
-
- The OPTIONAL [CHARSET] specification consists of the word "CHARSET"
- followed by the name of a character set from the registry
- [CHARSET-REG]. It indicates the [CHARSET] of the strings that appear
- in the search criteria. [MIME-IMB] content transfer encodings and
- [MIME-HDRS] strings in [RFC5322]/[MIME-IMB] headers MUST be decoded
- before comparing text. Servers MUST support US-ASCII and UTF-8
- charsets; other CHARSETs MAY be supported. Clients SHOULD use UTF-8.
- Note that if CHARSET is not provided, IMAP4rev2 servers MUST assume
- UTF-8, so selecting CHARSET UTF-8 is redundant. It is permitted for
- improved compatibility with existing IMAP4rev1 clients.
-
- If the server does not support the specified [CHARSET], it MUST
- return a tagged NO response (not a BAD). This response SHOULD
- contain the BADCHARSET response code, which MAY list the CHARSETs
- supported by the server.
-
- In all search keys that use strings, and unless otherwise specified,
- a message matches the key if the string is a substring of the
- associated text. The matching SHOULD be case insensitive for
- characters within the ASCII range. Consider using [IMAP-I18N] for
- language-sensitive, case-insensitive searching. Note that the empty
- string is a substring; this is useful when performing a HEADER search
- in order to test for a header field presence in the message.
-
- The defined search keys are as follows. Refer to "Formal Syntax"
- (Section 9) for the precise syntactic definitions of the arguments.
-
-
- Messages with message sequence numbers corresponding to the
- specified message sequence number set.
-
- ALL
- All messages in the mailbox; the default initial key for ANDing.
-
- ANSWERED
- Messages with the \Answered flag set.
-
- BCC
- Messages that contain the specified string in the envelope
- structure's Blind Carbon Copy (BCC) field.
-
- BEFORE
- Messages whose internal date (disregarding time and timezone) is
- earlier than the specified date.
-
- BODY
- Messages that contain the specified string in the body of the
- message. Unlike TEXT (see below), this doesn't match any header
- fields. Servers are allowed to implement flexible matching for
- this search key, for example, by matching "swim" to both "swam"
- and "swum" in English language text or only performing full word
- matching (where "swim" will not match "swimming").
-
- CC
- Messages that contain the specified string in the envelope
- structure's CC field.
-
- DELETED
- Messages with the \Deleted flag set.
-
- DRAFT
- Messages with the \Draft flag set.
-
- FLAGGED
- Messages with the \Flagged flag set.
-
- FROM
- Messages that contain the specified string in the envelope
- structure's FROM field.
-
- HEADER
- Messages that have a header field with the specified field-name
- (as defined in [RFC5322]) and that contain the specified string in
- the text of the header field (what comes after the colon). If the
- string to search is zero-length, this matches all messages that
- have a header field with the specified field-name regardless of
- the contents. Servers should use a substring search for this
- SEARCH item, as clients can use it for automatic processing not
- initiated by end users. For example, this can be used when
- searching for Message-ID or Content-Type header field values that
- need to be exact or for searches in header fields that the IMAP
- server might not know anything about.
-
- KEYWORD
- Messages with the specified keyword flag set.
-
- LARGER
- Messages with an RFC822.SIZE larger than the specified number of
- octets.
-
- NOT
- Messages that do not match the specified search key.
-
- ON
- Messages whose internal date (disregarding time and timezone) is
- within the specified date.
-
- OR
- Messages that match either search key.
-
- SEEN
- Messages that have the \Seen flag set.
-
- SENTBEFORE
- Messages whose [RFC5322] Date: header field (disregarding time and
- timezone) is earlier than the specified date.
-
- SENTON
- Messages whose [RFC5322] Date: header field (disregarding time and
- timezone) is within the specified date.
-
- SENTSINCE
- Messages whose [RFC5322] Date: header field (disregarding time and
- timezone) is within or later than the specified date.
-
- SINCE
- Messages whose internal date (disregarding time and timezone) is
- within or later than the specified date.
-
- SMALLER
- Messages with an RFC822.SIZE smaller than the specified number of
- octets.
-
- SUBJECT
- Messages that contain the specified string in the envelope
- structure's SUBJECT field.
-
- TEXT
- Messages that contain the specified string in the header
- (including MIME header fields) or body of the message. Servers
- are allowed to implement flexible matching for this search key,
- for example, matching "swim" to both "swam" and "swum" in English
- language text or only performing full-word matching (where "swim"
- will not match "swimming").
-
- TO
- Messages that contain the specified string in the envelope
- structure's TO field.
-
- UID
- Messages with unique identifiers corresponding to the specified
- unique identifier set. Sequence-set ranges are permitted.
-
- UNANSWERED
- Messages that do not have the \Answered flag set.
-
- UNDELETED
- Messages that do not have the \Deleted flag set.
-
- UNDRAFT
- Messages that do not have the \Draft flag set.
-
- UNFLAGGED
- Messages that do not have the \Flagged flag set.
-
- UNKEYWORD
- Messages that do not have the specified keyword flag set.
-
- UNSEEN
- Messages that do not have the \Seen flag set.
-
- Example:
-
- C: A282 SEARCH RETURN (MIN COUNT) FLAGGED
- SINCE 1-Feb-1994 NOT FROM "Smith"
- S: * ESEARCH (TAG "A282") MIN 2 COUNT 3
- S: A282 OK SEARCH completed
-
- Example:
-
- C: A283 SEARCH RETURN () FLAGGED
- SINCE 1-Feb-1994 NOT FROM "Smith"
- S: * ESEARCH (TAG "A283") ALL 2,10:11
- S: A283 OK SEARCH completed
-
- Example:
-
- C: A284 SEARCH TEXT "string not in mailbox"
- S: * ESEARCH (TAG "A284")
- S: A284 OK SEARCH completed
- C: A285 SEARCH CHARSET UTF-8 TEXT {12}
- S: + Ready for literal text
- C: отпуск
- S: * ESEARCH (TAG "A285") ALL 43
- S: A285 OK SEARCH completed
-
-
- The following example demonstrates finding the first unseen message
- in the mailbox:
-
- Example:
-
- C: A284 SEARCH RETURN (MIN) UNSEEN
- S: * ESEARCH (TAG "A284") MIN 4
- S: A284 OK SEARCH completed
-
- The following example demonstrates that if the ESEARCH UID indicator
- is present, all data in the ESEARCH response is referring to UIDs;
- for example, the MIN result specifier will be followed by a UID.
-
- Example:
-
- C: A285 UID SEARCH RETURN (MIN MAX) 1:5000
- S: * ESEARCH (TAG "A285") UID MIN 7 MAX 3800
- S: A285 OK SEARCH completed
-
- The following example demonstrates returning the number of deleted
- messages:
-
- Example:
-
- C: A286 SEARCH RETURN (COUNT) DELETED
- S: * ESEARCH (TAG "A286") COUNT 15
- S: A286 OK SEARCH completed
-
-6.4.4.1. SAVE Result Option and SEARCH Result Variable
-
- Upon successful completion of a SELECT or an EXAMINE command (after
- the tagged OK response), the current search result variable is reset
- to the empty sequence.
-
- A successful SEARCH command with the SAVE result option sets the
- value of the search result variable to the list of messages found in
- the SEARCH command. For example, if no messages were found, the
- search result variable will contain the empty sequence.
-
- Any of the following SEARCH commands MUST NOT change the search
- result variable:
-
- a SEARCH command that caused the server to return the BAD tagged
- response,
-
- a SEARCH command with no SAVE result option that caused the server
- to return NO tagged response, and
-
- a successful SEARCH command with no SAVE result option.
-
- A SEARCH command with the SAVE result option that caused the server
- to return the NO tagged response sets the value of the search result
- variable to the empty sequence.
-
- When a message listed in the search result variable is EXPUNGEd, it
- is automatically removed from the list. Implementors are reminded
- that if the server stores the list as a list of message numbers, it
- MUST automatically adjust them when notifying the client about
- expunged messages, as described in Section 7.5.1.
-
- If the server decides to send a new UIDVALIDITY value while the
- mailbox is opened, it causes the resetting of the search variable to
- the empty sequence.
-
- Note that even if the "$" marker contains the empty sequence of
- messages, it must be treated by all commands accepting message sets
- as parameters as a valid, but non-matching, list of messages. For
- example, the "FETCH $" command would return a tagged OK response and
- no FETCH responses. See also Example 5 in Section 6.4.4.4.
-
- The SAVE result option doesn't change whether the server would return
- items corresponding to MIN, MAX, ALL, or COUNT result options.
-
- When the SAVE result option is combined with the MIN or MAX result
- option, and both ALL and COUNT result options are absent, the
- corresponding MIN/MAX is returned (if the search result is not
- empty), but the "$" marker would contain a single message as returned
- in the MIN/MAX return item.
-
- If the SAVE result option is combined with both MIN and MAX result
- options, and both ALL and COUNT result options are absent, the "$"
- marker would contain zero messages, one message, or two messages as
- returned in the MIN/MAX return items.
-
- If the SAVE result option is combined with the ALL and/or COUNT
- result option(s), the "$" marker would always contain all messages
- found by the SEARCH or UID SEARCH command.
-
- The following table summarizes the additional requirement on ESEARCH
- server implementations described in this section.
-
- +==============================+====================+
- | Combination of Result Option | "$" Marker Value |
- +==============================+====================+
- | SAVE MIN | MIN |
- +------------------------------+--------------------+
- | SAVE MAX | MAX |
- +------------------------------+--------------------+
- | SAVE MIN MAX | MIN & MAX |
- +------------------------------+--------------------+
- | SAVE * [m] | all found messages |
- +------------------------------+--------------------+
-
- Table 4
-
- where '*' means "ALL" and/or "COUNT", and '[m]' means optional "MIN"
- and/or "MAX"
-
- Implementation note: server implementors should note that "$" can
- reference IMAP message sequences or UID sequences, depending on the
- context where it is used. For example, the "$" marker can be set as
- a result of a SEARCH (SAVE) command and used as a parameter to a UID
- FETCH command (which accepts a UID sequence, not a message sequence),
- or the "$" marker can be set as a result of a UID SEARCH (SAVE)
- command and used as a parameter to a FETCH command (which accepts a
- message sequence, not a UID sequence). Server implementations need
- to automatically map the "$" marker value to message numbers or UIDs,
- depending on the context where the "$" marker is used.
-
-6.4.4.2. Multiple Commands in Progress
-
- Use of a SEARCH RETURN (SAVE) command followed by a command using the
- "$" marker creates direct dependency between the two commands. As
- directed by Section 5.5, a server MUST execute the two commands in
- the order they were received.
-
- A client MAY pipeline a SEARCH RETURN (SAVE) command with one or more
- commands using the "$" marker, as long as this doesn't create an
- ambiguity, as described in Section 5.5. Examples 7-9 in
- Section 6.4.4.4 explain this in more details.
-
-6.4.4.3. Refusing to Save Search Results
-
- In some cases, the server MAY refuse to save a SEARCH (SAVE) result,
- for example, if an internal limit on the number of saved results is
- reached. In this case, the server MUST return a tagged NO response
- containing the NOTSAVED response code and set the search result
- variable to the empty sequence, as described in Section 6.4.4.1.
-
-6.4.4.4. Examples Showing Use of the SAVE Result Option
-
- Only in this section: explanatory comments in examples that start
- with // are not part of the protocol.
-
- 1. The following example demonstrates how the client can use the
- result of a SEARCH command to FETCH headers of interesting
- messages:
-
- Example 1:
-
- C: A282 SEARCH RETURN (SAVE) FLAGGED SINCE 1-Feb-1994
- NOT FROM "Smith"
- S: A282 OK SEARCH completed, result saved
- C: A283 FETCH $ (UID INTERNALDATE FLAGS BODY.PEEK[HEADER])
- S: * 2 FETCH (UID 14 ...
- S: * 84 FETCH (UID 100 ...
- S: * 882 FETCH (UID 1115 ...
- S: A283 OK completed
-
- The client can also pipeline the two commands:
-
- Example 2:
-
- C: A282 SEARCH RETURN (SAVE) FLAGGED SINCE 1-Feb-1994
- NOT FROM "Smith"
- C: A283 FETCH $ (UID INTERNALDATE FLAGS BODY.PEEK[HEADER])
- S: A282 OK SEARCH completed
- S: * 2 FETCH (UID 14 ...
- S: * 84 FETCH (UID 100 ...
- S: * 882 FETCH (UID 1115 ...
- S: A283 OK completed
-
- 2. The following example demonstrates that the result of one SEARCH
- command can be used as input to another SEARCH command:
-
- Example 3:
-
- C: A300 SEARCH RETURN (SAVE) SINCE 1-Jan-2004
- NOT FROM "Smith"
- S: A300 OK SEARCH completed
- C: A301 UID SEARCH UID $ SMALLER 4096
- S: * ESEARCH (TAG "A301") UID ALL 17,900,901
- S: A301 OK completed
-
- Note that the second command in Example 3 can be replaced with:
-
- C: A301 UID SEARCH $ SMALLER 4096
-
- and the result of the command would be the same.
-
- 3. The following example shows that the "$" marker can be combined
- with other message numbers using the OR SEARCH criterion.
-
- Example 4:
-
- C: P282 SEARCH RETURN (SAVE) SINCE 1-Feb-1994
- NOT FROM "Smith"
- S: P282 OK SEARCH completed
- C: P283 SEARCH CHARSET UTF-8 (OR $ 1,3000:3021) TEXT {8+}
- C: мать
- S: * ESEARCH (TAG "P283") ALL 882,1102,3003,3005:3006
- S: P283 OK completed
-
- 4. The following example demonstrates that a failed SEARCH sets the
- search result variable to the empty list. The server doesn't
- implement the KOI8-R charset.
-
- Example 5:
-
- C: B282 SEARCH RETURN (SAVE) SINCE 1-Feb-1994
- NOT FROM "Smith"
- S: B282 OK SEARCH completed
- C: B283 SEARCH RETURN (SAVE) CHARSET KOI8-R
- (OR $ 1,3000:3021) TEXT {4}
- C: XXXX
- S: B283 NO [BADCHARSET UTF-8] KOI8-R is not supported
- //After this command, the saved result variable contains
- //no messages. A client that wants to reissue the B283
- //SEARCH command with another CHARSET would have to reissue
- //the B282 command as well. One possible workaround for
- //this is to include the desired CHARSET parameter
- //in the earliest SEARCH RETURN (SAVE) command in a
- //sequence of related SEARCH commands, to cause
- //the earliest SEARCH in the sequence to fail.
- //A better approach might be to always use CHARSET UTF-8
- //instead.
-
- Note: Since this document format is restricted to 7-bit ASCII
- text, it is not possible to show actual KOI8-R data. The "XXXX"
- is a placeholder for what would be 4 octets of 8-bit data in an
- actual transaction.
-
- 5. The following example demonstrates that it is not an error to use
- the "$" marker when it contains no messages.
-
- Example 6:
-
- C: E282 SEARCH RETURN (SAVE) SINCE 28-Oct-2006
- NOT FROM "Eric"
- C: E283 COPY $ "Other Messages"
- //The "$" contains no messages
- S: E282 OK SEARCH completed
- S: E283 OK COPY completed, nothing copied
-
- Example 7:
-
- C: F282 SEARCH RETURN (SAVE) KEYWORD $Junk
- C: F283 COPY $ "Junk"
- C: F284 STORE $ +FLAGS.Silent (\Deleted)
- S: F282 OK SEARCH completed
- S: F283 OK COPY completed
- S: F284 OK STORE completed
-
- Example 8:
-
- C: G282 SEARCH RETURN (SAVE) KEYWORD $Junk
- C: G283 SEARCH RETURN (ALL) SINCE 28-Oct-2006
- FROM "Eric"
- // The server can execute the two SEARCH commands
- // in any order, as they don't have any dependency.
- // For example, it may return:
- S: * ESEARCH (TAG "G283") ALL 3:15,27,29:103
- S: G283 OK SEARCH completed
- S: G282 OK SEARCH completed
-
- The following example demonstrates that the result of the second
- SEARCH RETURN (SAVE) always overrides the result of the first.
-
- Example 9:
-
- C: H282 SEARCH RETURN (SAVE) KEYWORD $Junk
- C: H283 SEARCH RETURN (SAVE) SINCE 28-Oct-2006
- FROM "Eric"
- S: H282 OK SEARCH completed
- S: H283 OK SEARCH completed
- // At this point "$" would contain results of H283
-
- The following example demonstrates behavioral difference for
- different combinations of ESEARCH result options.
-
- Example 10:
-
- C: C282 SEARCH RETURN (ALL) SINCE 12-Feb-2006
- NOT FROM "Smith"
- S: * ESEARCH (TAG "C283") ALL 2,10:15,21
- //$ value hasn't changed
- S: C282 OK SEARCH completed
-
- C: C283 SEARCH RETURN (ALL SAVE) SINCE 12-Feb-2006
- NOT FROM "Smith"
- S: * ESEARCH (TAG "C283") ALL 2,10:15,21
- //$ value is 2,10:15,21
- S: C283 OK SEARCH completed
-
- C: C284 SEARCH RETURN (SAVE MIN) SINCE 12-Feb-2006
- NOT FROM "Smith"
- S: * ESEARCH (TAG "C284") MIN 2
- //$ value is 2
- S: C284 OK SEARCH completed
-
- C: C285 SEARCH RETURN (MAX SAVE MIN) SINCE
- 12-Feb-2006 NOT FROM "Smith"
- S: * ESEARCH (TAG "C285") MIN 2 MAX 21
- //$ value is 2,21
- S: C285 OK SEARCH completed
-
- C: C286 SEARCH RETURN (MAX SAVE MIN COUNT)
- SINCE 12-Feb-2006 NOT FROM "Smith"
- S: * ESEARCH (TAG "C286") MIN 2 MAX 21 COUNT 8
- //$ value is 2,10:15,21
- S: C286 OK SEARCH completed
-
- C: C286 SEARCH RETURN (ALL SAVE MIN) SINCE
- 12-Feb-2006 NOT FROM "Smith"
- S: * ESEARCH (TAG "C286") MIN 2 ALL 2,10:15,21
- //$ value is 2,10:15,21
- S: C286 OK SEARCH completed
-
-6.4.5. FETCH Command
-
- Arguments: sequence set
-
- message data item names or macro
-
- Responses: untagged responses: FETCH
-
- Result: OK - fetch completed
- NO - fetch error: can't fetch that data
- BAD - command unknown or arguments invalid
-
- The FETCH command retrieves data associated with a message in the
- mailbox. The data items to be fetched can be either a single atom or
- a parenthesized list.
-
- Most data items, identified in the formal syntax (Section 9) under
- the msg-att-static rule, are static and MUST NOT change for any
- particular message. Other data items, identified in the formal
- syntax under the msg-att-dynamic rule, MAY change either as a result
- of a STORE command or due to external events.
-
- For example, if a client receives an ENVELOPE for a message when
- it already knows the envelope, it can safely ignore the newly
- transmitted envelope.
-
- There are three macros that specify commonly used sets of data items
- and can be used instead of data items. A macro must be used by
- itself and not in conjunction with other macros or data items.
-
- ALL
- Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE)
-
- FAST
- Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE)
-
- FULL
- Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE
- BODY)
-
- Several data items reference "section" or "section-binary". See
- Section 6.4.5.1 for their detailed definition.
-
- The currently defined data items that can be fetched are:
-
- BINARY[]<>
- Requests that the specified section be transmitted after
- performing decoding of the section's Content-Transfer-Encoding.
-
- The argument, if present, requests that a subset of the
- data be returned. The semantics of a partial FETCH BINARY command
- are the same as for a partial FETCH BODY command, with the
- exception that the arguments refer to the DECODED
- section data.
-
- Note that this data item can only be requested for leaf body
- parts: those that have media types other than multipart/*,
- message/rfc822, or message/global.
-
- BINARY.PEEK[]<>
- An alternate form of BINARY[] that does not
- implicitly set the \Seen flag.
-
- BINARY.SIZE[]
- Requests the decoded size of the section (i.e., the size to expect
- in response to the corresponding FETCH BINARY request).
-
- Note: client authors are cautioned that this might be an expensive
- operation for some server implementations. Needlessly issuing
- this request could result in degraded performance due to servers
- having to calculate the value every time the request is issued.
-
- Note that this data item can only be requested for leaf body
- parts: those that have media types other than multipart/*,
- message/rfc822, or message/global.
-
- BODY
- Non-extensible form of BODYSTRUCTURE.
-
- BODY[]<>
- The text of a particular body section. If BODY[] is specified
- (the section specification is omitted), the FETCH is requesting
- the [RFC5322] expression of the entire message.
-
- It is possible to fetch a substring of the designated text. This
- is done by appending an open angle bracket ("<"), the octet
- position of the first desired octet, a period, the maximum number
- of octets desired, and a close angle bracket (">") to the part
- specifier. If the starting octet is beyond the end of the text,
- an empty string is returned.
-
- Any partial fetch that attempts to read beyond the end of the text
- is truncated as appropriate. A partial fetch that starts at octet
- 0 is returned as a partial fetch, even if this truncation
- happened.
-
- Note: This means that BODY[]<0.2048> of a 1500-octet message
- will return BODY[]<0> with a literal of size 1500, not BODY[].
-
- Note: A substring fetch of a HEADER.FIELDS or HEADER.FIELDS.NOT
- part specifier is calculated after subsetting the header.
-
- The \Seen flag is implicitly set; if this causes the flags to
- change, they SHOULD be included as part of the FETCH responses.
-
- BODY.PEEK[]<>
- An alternate form of BODY[] that does not implicitly set
- the \Seen flag.
-
- BODYSTRUCTURE
- The [MIME-IMB] body structure of the message. This is computed by
- the server by parsing the [MIME-IMB] header fields in the
- [RFC5322] header and [MIME-IMB] headers. See Section 7.5.2 for
- more details.
-
- ENVELOPE
- The envelope structure of the message. This is computed by the
- server by parsing the [RFC5322] header into the component parts,
- defaulting various fields as necessary. See Section 7.5.2 for
- more details.
-
- FLAGS
- The flags that are set for this message.
-
- INTERNALDATE
- The internal date of the message.
-
- RFC822.SIZE
- The size of the message, as defined in Section 2.3.4.
-
- UID
- The unique identifier for the message.
-
- Example:
-
- C: A654 FETCH 2:4 (FLAGS BODY[HEADER.FIELDS (DATE FROM)])
- S: * 2 FETCH ....
- S: * 3 FETCH ....
- S: * 4 FETCH ....
- S: A654 OK FETCH completed
-
-6.4.5.1. FETCH Section Specification
-
- Several FETCH data items reference "section" or "section-binary".
- The section specification is a set of zero or more part specifiers
- delimited by periods. A part specifier is either a part number or
- one of the following: HEADER, HEADER.FIELDS, HEADER.FIELDS.NOT, MIME,
- and TEXT. (Non-numeric part specifiers have to be the last specifier
- in a section specification.) An empty section specification refers
- to the entire message, including the header.
-
- Every message has at least one part number. Messages that do not use
- MIME, and MIME messages that are not multipart and have no
- encapsulated message within them, only have a part 1.
-
- Multipart messages are assigned consecutive part numbers, as they
- occur in the message. If a particular part is of type message or
- multipart, its parts MUST be indicated by a period followed by the
- part number within that nested multipart part.
-
- A part of type MESSAGE/RFC822 or MESSAGE/GLOBAL also has nested part
- numbers, referring to parts of the MESSAGE part's body.
-
- The HEADER, HEADER.FIELDS, HEADER.FIELDS.NOT, and TEXT part
- specifiers can be the sole part specifier or can be prefixed by one
- or more numeric part specifiers, provided that the numeric part
- specifier refers to a part of type MESSAGE/RFC822 or MESSAGE/GLOBAL.
- The MIME part specifier MUST be prefixed by one or more numeric part
- specifiers.
-
- The HEADER, HEADER.FIELDS, and HEADER.FIELDS.NOT part specifiers
- refer to the [RFC5322] header of the message or of an encapsulated
- [MIME-IMT] MESSAGE/RFC822 or MESSAGE/GLOBAL message. HEADER.FIELDS
- and HEADER.FIELDS.NOT are followed by a list of field-names (as
- defined in [RFC5322]) and return a subset of the header. The subset
- returned by HEADER.FIELDS contains only those header fields with a
- field-name that matches one of the names in the list; similarly, the
- subset returned by HEADER.FIELDS.NOT contains only the header fields
- with a non-matching field-name. The field-matching is ASCII-range
- case insensitive but is otherwise exact. Subsetting does not exclude
- the [RFC5322] delimiting blank line between the header and the body;
- the blank line is included in all header fetches, except in the case
- of a message that has no body and no blank line.
-
- The MIME part specifier refers to the [MIME-IMB] header for this
- part.
-
- The TEXT part specifier refers to the text body of the message,
- omitting the [RFC5322] header.
-
- Here is an example of a complex message with some of its part
- specifiers:
-
- HEADER ([RFC5322] header of the message)
- TEXT ([RFC5322] text body of the message) MULTIPART/MIXED
- 1 TEXT/PLAIN
- 2 APPLICATION/OCTET-STREAM
- 3 MESSAGE/RFC822
- 3.HEADER ([RFC5322] header of the message)
- 3.TEXT ([RFC5322] text body of the message) MULTIPART/MIXED
- 3.1 TEXT/PLAIN
- 3.2 APPLICATION/OCTET-STREAM
- 4 MULTIPART/MIXED
- 4.1 IMAGE/GIF
- 4.1.MIME ([MIME-IMB] header for the IMAGE/GIF)
- 4.2 MESSAGE/RFC822
- 4.2.HEADER ([RFC5322] header of the message)
- 4.2.TEXT ([RFC5322] text body of the message) MULTIPART/MIXED
- 4.2.1 TEXT/PLAIN
- 4.2.2 MULTIPART/ALTERNATIVE
- 4.2.2.1 TEXT/PLAIN
- 4.2.2.2 TEXT/RICHTEXT
-
-6.4.6. STORE Command
-
- Arguments: sequence set
-
- message data item name
-
- value for message data item
-
- Responses: untagged responses: FETCH
-
- Result: OK - store completed
- NO - store error: can't store that data
- BAD - command unknown or arguments invalid
-
- The STORE command alters data associated with a message in the
- mailbox. Normally, STORE will return the updated value of the data
- with an untagged FETCH response. A suffix of ".SILENT" in the data
- item name prevents the untagged FETCH, and the server SHOULD assume
- that the client has determined the updated value itself or does not
- care about the updated value.
-
- Note: Regardless of whether or not the ".SILENT" suffix was used,
- the server SHOULD send an untagged FETCH response if a change to a
- message's flags from an external source is observed. The intent
- is that the status of the flags is determinate without a race
- condition.
-
- The currently defined data items that can be stored are:
-
- FLAGS
- Replace the flags for the message with the argument. The new
- value of the flags is returned as if a FETCH of those flags was
- done.
-
- FLAGS.SILENT
- Equivalent to FLAGS, but without returning a new value.
-
- +FLAGS
- Add the argument to the flags for the message. The new value of
- the flags is returned as if a FETCH of those flags was done.
-
- +FLAGS.SILENT
- Equivalent to +FLAGS, but without returning a new value.
-
- -FLAGS
- Remove the argument from the flags for the message. The new value
- of the flags is returned as if a FETCH of those flags was done.
-
- -FLAGS.SILENT
- Equivalent to -FLAGS, but without returning a new value.
-
- Example:
-
- C: A003 STORE 2:4 +FLAGS (\Deleted)
- S: * 2 FETCH (FLAGS (\Deleted \Seen))
- S: * 3 FETCH (FLAGS (\Deleted))
- S: * 4 FETCH (FLAGS (\Deleted \Flagged \Seen))
- S: A003 OK STORE completed
-
-6.4.7. COPY Command
-
- Arguments: sequence set
-
- mailbox name
-
- Responses: no specific responses for this command
-
- Result: OK - copy completed
- NO - copy error: can't copy those messages or to that
- name
- BAD - command unknown or arguments invalid
-
- The COPY command copies the specified message(s) to the end of the
- specified destination mailbox. The flags and internal date of the
- message(s) SHOULD be preserved in the copy.
-
- If the destination mailbox does not exist, a server MUST return an
- error. It MUST NOT automatically create the mailbox. Unless it is
- certain that the destination mailbox can not be created, the server
- MUST send the response code "[TRYCREATE]" as the prefix of the text
- of the tagged NO response. This gives a hint to the client that it
- can attempt a CREATE command and retry the COPY if the CREATE is
- successful.
-
- If the COPY command is unsuccessful for any reason, server
- implementations MUST restore the destination mailbox to its state
- before the COPY attempt (other than possibly incrementing UIDNEXT),
- i.e., partial copy MUST NOT be done.
-
- On successful completion of a COPY, the server returns a COPYUID
- response code (see Section 7.1). Two exceptions to this requirement
- are listed below.
-
- In the case of a mailbox that has permissions set so that the client
- can COPY to the mailbox, but not SELECT or EXAMINE it, the server
- MUST NOT send a COPYUID response code as it would disclose
- information about the mailbox.
-
- In the case of a mailbox that has UIDNOTSTICKY status (see
- Section 7.1), the server MAY omit the COPYUID response code as it is
- not meaningful.
-
- Example:
-
- C: A003 COPY 2:4 MEETING
- S: A003 OK [COPYUID 38505 304,319:320 3956:3958] COPY completed
-
-6.4.8. MOVE Command
-
- Arguments: sequence set
-
- mailbox name
-
- Responses: no specific responses for this command
-
- Result: OK - move completed
- NO - move error: can't move those messages or to that
- name
- BAD - command unknown or arguments invalid
-
- The MOVE command moves the specified message(s) to the end of the
- specified destination mailbox. The flags and internal date of the
- message(s) SHOULD be preserved.
-
- This means that a new message is created in the target mailbox with a
- new UID, the original message is removed from the source mailbox, and
- it appears to the client as a single action. This has the same
- effect for each message as this sequence:
-
- 1. [UID] COPY
-
- 2. [UID] STORE +FLAGS.SILENT \DELETED
-
- 3. UID EXPUNGE
-
- Although the effect of the MOVE is the same as the preceding steps,
- the semantics are not identical: the intermediate states produced by
- those steps do not occur, and the response codes are different. In
- particular, though the COPY and EXPUNGE response codes will be
- returned, response codes for a STORE MUST NOT be generated, and the
- \Deleted flag MUST NOT be set for any message.
-
- Unlike the COPY command, MOVE of a set of messages might fail partway
- through the set. Regardless of whether the command is successful in
- moving the entire set, each individual message MUST be either moved
- or unaffected. The server MUST leave each message in a state where
- it is in at least one of the source or target mailboxes (no message
- can be lost or orphaned). The server SHOULD NOT leave any message in
- both mailboxes (it would be bad for a partial failure to result in a
- bunch of duplicate messages). This is true even if the server
- returns a tagged NO response to the command.
-
- If the destination mailbox does not exist, a server MUST return an
- error. It MUST NOT automatically create the mailbox. Unless it is
- certain that the destination mailbox cannot be created, the server
- MUST send the response code "[TRYCREATE]" as the prefix of the text
- of the tagged NO response. This gives a hint to the client that it
- can attempt a CREATE command and retry the MOVE if the CREATE is
- successful.
-
- Because of the similarity of MOVE to COPY, extensions that affect
- COPY affect MOVE in the same way. Response codes listed in
- Section 7.1, as well as those defined by extensions, are sent as
- indicated for COPY.
-
- Servers send COPYUID in response to a MOVE or a UID MOVE (see
- Section 6.4.9) command. For additional information about COPYUID,
- see Section 7.1. Note that there are several exceptions listed in
- Section 6.4.7 that allow servers not to return COPYUID.
-
- Servers are also REQUIRED to send the COPYUID response code in an
- untagged OK before sending EXPUNGE or similar responses. (Sending
- COPYUID in the tagged OK, as described in Section 6.4.7, means that
- clients first receive an EXPUNGE for a message and afterwards COPYUID
- for the same message. It can be unnecessarily difficult to process
- that sequence usefully.)
-
- An example:
-
- C: a UID MOVE 42:69 foo
- S: * OK [COPYUID 432432 42:69 1202:1229]
- S: * 22 EXPUNGE
- ...More EXPUNGE responses from the server...
- S: a OK Done
-
- Note that the server may send unrelated EXPUNGE responses as well, if
- any happen to have been expunged at the same time; this is normal
- IMAP operation.
-
- Note that moving a message to the currently selected mailbox (that
- is, where the source and target mailboxes are the same) is allowed
- when copying the message to the currently selected mailbox is
- allowed.
-
- The server may send EXPUNGE responses before the tagged response, so
- the client cannot safely send more commands with message sequence
- number arguments while the server is processing MOVE.
-
- MOVE and UID MOVE can be pipelined with other commands, but care has
- to be taken. Both commands modify sequence numbers and also allow
- unrelated EXPUNGE responses. The renumbering of other messages in
- the source mailbox following any EXPUNGE response can be surprising
- and makes it unsafe to pipeline any command that relies on message
- sequence numbers after a MOVE or UID MOVE. Similarly, MOVE cannot be
- pipelined with a command that might cause message renumbering. See
- Section 5.5 for more information about ambiguities as well as
- handling requirements for both clients and servers.
-
-6.4.9. UID Command
-
- Arguments: command name
-
- command arguments
-
- Responses: untagged responses: FETCH, ESEARCH, EXPUNGE
-
- Result: OK - UID command completed
- NO - UID command error
- BAD - command unknown or arguments invalid
-
- The UID command has three forms. In the first form, it takes as its
- arguments a COPY, MOVE, FETCH, or STORE command with arguments
- appropriate for the associated command. However, the numbers in the
- sequence-set argument are unique identifiers instead of message
- sequence numbers. Sequence-set ranges are permitted, but there is no
- guarantee that unique identifiers will be contiguous.
-
- A non-existent unique identifier is ignored without any error message
- generated. Thus, it is possible for a UID FETCH command to return an
- OK without any data or a UID COPY, UID MOVE, or UID STORE to return
- an OK without performing any operations.
-
- In the second form, the UID command takes an EXPUNGE command with an
- extra parameter that specifies a sequence set of UIDs to operate on.
- The UID EXPUNGE command permanently removes all messages that have
- both the \Deleted flag set and a UID that is included in the
- specified sequence set from the currently selected mailbox. If a
- message either does not have the \Deleted flag set or has a UID that
- is not included in the specified sequence set, it is not affected.
-
- UID EXPUNGE is particularly useful for disconnected use clients. By
- using UID EXPUNGE instead of EXPUNGE when resynchronizing with the
- server, the client can ensure that it does not inadvertently remove
- any messages that have been marked as \Deleted by other clients
- between the time that the client was last connected and the time the
- client resynchronizes.
-
- Example:
-
- C: A003 UID EXPUNGE 3000:3002
- S: * 3 EXPUNGE
- S: * 3 EXPUNGE
- S: * 3 EXPUNGE
- S: A003 OK UID EXPUNGE completed
-
- In the third form, the UID command takes a SEARCH command with SEARCH
- command arguments. The interpretation of the arguments is the same
- as with SEARCH; however, the numbers returned in an ESEARCH response
- for a UID SEARCH command are unique identifiers instead of message
- sequence numbers. Also, the corresponding ESEARCH response MUST
- include the UID indicator. For example, the command UID SEARCH 1:100
- UID 443:557 returns the unique identifiers corresponding to the
- intersection of two sequence sets, the message sequence number range
- 1:100, and the UID range 443:557.
-
- Note: in the above example, the UID range 443:557 appears. The
- same comment about a non-existent unique identifier being ignored
- without any error message also applies here. Hence, even if
- neither UID 443 or 557 exist, this range is valid and would
- include an existing UID 495.
-
- Also note that a UID range of 559:* always includes the UID of the
- last message in the mailbox, even if 559 is higher than any
- assigned UID value. This is because the contents of a range are
- independent of the order of the range endpoints. Thus, any UID
- range with * as one of the endpoints indicates at least one
- message (the message with the highest numbered UID), unless the
- mailbox is empty.
-
- The number after the "*" in an untagged FETCH or EXPUNGE response is
- always a message sequence number, not a unique identifier, even for a
- UID command response. However, server implementations MUST
- implicitly include the UID message data item as part of any FETCH
- response caused by a UID command, regardless of whether a UID was
- specified as a message data item to the FETCH.
-
- Note: The rule about including the UID message data item as part of a
- FETCH response primarily applies to the UID FETCH and UID STORE
- commands, including a UID FETCH command that does not include UID as
- a message data item. Although it is unlikely that the other UID
- commands will cause an untagged FETCH, this rule applies to these
- commands as well.
-
- Example:
-
- C: A999 UID FETCH 4827313:4828442 FLAGS
- S: * 23 FETCH (FLAGS (\Seen) UID 4827313)
- S: * 24 FETCH (FLAGS (\Seen) UID 4827943)
- S: * 25 FETCH (FLAGS (\Seen) UID 4828442)
- S: A999 OK UID FETCH completed
-
-6.5. Client Commands - Experimental/Expansion
-
- Each command that is not part of this specification MUST have at
- least one capability name (see Section 6.1.1) associated with it.
- (Multiple commands can be associated with the same capability name.)
-
- Server implementations MUST NOT send any added untagged responses
- (not specified in this specification), unless the client requested it
- by issuing the associated experimental command (specified in an
- extension document) or the ENABLE command (Section 6.3.1).
-
- The following example demonstrates how a client can check for the
- presence of a fictitious XPIG-LATIN capability that adds the XPIG-
- LATIN command and the XPIG-LATIN untagged response. (Note that for
- an extension, the command name and the capability name don't have to
- be the same.)
-
- Example:
-
- C: a441 CAPABILITY
- S: * CAPABILITY IMAP4rev2 XPIG-LATIN
- S: a441 OK CAPABILITY completed
- C: A442 XPIG-LATIN
- S: * XPIG-LATIN ow-nay eaking-spay ig-pay atin-lay
- S: A442 OK XPIG-LATIN ompleted-cay
-
-7. Server Responses
-
- Server responses are in three forms: status responses, server data,
- and command continuation requests. The information contained in a
- server response, identified by "Contents:" in the response
- descriptions below, is described by function, not by syntax. The
- precise syntax of server responses is described in "Formal Syntax"
- (Section 9).
-
- The client MUST be prepared to accept any response at all times.
-
- Status responses can be tagged or untagged. Tagged status responses
- indicate the completion result (OK, NO, or BAD status) of a client
- command and have a tag matching the command.
-
- Some status responses, and all server data, are untagged. An
- untagged response is indicated by the token "*" instead of a tag.
- Untagged status responses indicate server greeting or server status
- that does not indicate the completion of a command (for example, an
- impending system shutdown alert). For historical reasons, untagged
- server data responses are also called "unsolicited data", although
- strictly speaking, only unilateral server data is truly
- "unsolicited".
-
- Certain server data MUST be remembered by the client when it is
- received; this is noted in the description of that data. Such data
- conveys critical information that affects the interpretation of all
- subsequent commands and responses (e.g., updates reflecting the
- creation or destruction of messages).
-
- Other server data SHOULD be remembered for later reference; if the
- client does not need to remember the data, or if remembering the data
- has no obvious purpose (e.g., a SEARCH response when no SEARCH
- command is in progress), the data can be ignored.
-
- An example of unilateral untagged server data occurs when the IMAP
- connection is in the selected state. In the selected state, the
- server checks the mailbox for new messages as part of command
- execution. Normally, this is part of the execution of every command;
- hence, a NOOP command suffices to check for new messages. If new
- messages are found, the server sends an untagged EXISTS response
- reflecting the new size of the mailbox. Server implementations that
- offer multiple simultaneous access to the same mailbox SHOULD also
- send appropriate unilateral untagged FETCH and EXPUNGE responses if
- another agent changes the state of any message flags or expunges any
- messages.
-
- Command continuation request responses use the token "+" instead of a
- tag. These responses are sent by the server to indicate acceptance
- of an incomplete client command and readiness for the remainder of
- the command.
-
-7.1. Server Responses - Generic Status Responses
-
- Status responses are OK, NO, BAD, PREAUTH, and BYE. OK, NO, and BAD
- can be tagged or untagged. PREAUTH and BYE are always untagged.
-
- Status responses MAY include an OPTIONAL "response code". A response
- code consists of data inside square brackets in the form of an atom,
- possibly followed by a space and arguments. The response code
- contains additional information or status codes for client software
- beyond the OK/NO/BAD condition and are defined when there is a
- specific action that a client can take based upon the additional
- information.
-
- The currently defined response codes are:
-
- ALERT
- The human-readable text contains a special alert that is presented
- to the user in a fashion that calls the user's attention to the
- message. Content of ALERT response codes received on a connection
- without TLS or SASL security-layer confidentiality SHOULD be
- ignored by clients. If displayed, such alerts MUST be clearly
- marked as potentially suspicious. (Note that some existing
- clients are known to hyperlink returned text, which make them very
- dangerous.) Alerts received after successful establishment of a
- TLS/SASL confidentiality layer MUST be presented to the user.
-
- ALREADYEXISTS
- The operation attempts to create something that already exists,
- such as when a CREATE or RENAME command attempts to create a
- mailbox and there is already one of that name.
-
- C: o356 RENAME this that
- S: o356 NO [ALREADYEXISTS] Mailbox "that" already exists
-
- APPENDUID
- Followed by the UIDVALIDITY of the destination mailbox and the UID
- assigned to the appended message in the destination mailbox, it
- indicates that the message has been appended to the destination
- mailbox with that UID.
-
- If the server also supports the [MULTIAPPEND] extension, and if
- multiple messages were appended in the APPEND command, then the
- second value is a UID set containing the UIDs assigned to the
- appended messages, in the order they were transmitted in the
- APPEND command. This UID set may not contain extraneous UIDs or
- the symbol "*".
-
- Note: the UID set form of the APPENDUID response code MUST NOT
- be used if only a single message was appended. In particular,
- a server MUST NOT send a range such as 123:123. This is
- because a client that does not support [MULTIAPPEND] expects
- only a single UID and not a UID set.
-
- UIDs are assigned in strictly ascending order in the mailbox
- (refer to Section 2.3.1.1); note that a range of 12:10 is exactly
- equivalent to 10:12 and refers to the sequence 10,11,12.
-
- This response code is returned in a tagged OK response to the
- APPEND command.
-
- AUTHENTICATIONFAILED
- Authentication failed for some reason on which the server is
- unwilling to elaborate. Typically, this includes "unknown user"
- and "bad password".
-
- This is the same as not sending any response code, except that
- when a client sees AUTHENTICATIONFAILED, it knows that the problem
- wasn't, e.g., UNAVAILABLE, so there's no point in trying the same
- login/password again later.
-
- C: b LOGIN "fred" "foo"
- S: b NO [AUTHENTICATIONFAILED] Authentication failed
-
- AUTHORIZATIONFAILED
- Authentication succeeded in using the authentication identity, but
- the server cannot or will not allow the authentication identity to
- act as the requested authorization identity. This is only
- applicable when the authentication and authorization identities
- are different.
-
- C: c1 AUTHENTICATE PLAIN
- [...]
- S: c1 NO [AUTHORIZATIONFAILED] No such authorization-ID
-
- C: c2 AUTHENTICATE PLAIN
- [...]
- S: c2 NO [AUTHORIZATIONFAILED] Authenticator is not an admin
-
- BADCHARSET
- Optionally followed by a parenthesized list of charsets. A SEARCH
- failed because the given charset is not supported by this
- implementation. If the optional list of charsets is given, this
- lists the charsets that are supported by this implementation.
-
- CANNOT
- This operation violates some invariant of the server and can never
- succeed.
-
- C: l create "///////"
- S: l NO [CANNOT] Adjacent slashes are not supported
-
- CAPABILITY
- Followed by a list of capabilities. This can appear in the
- initial OK or PREAUTH response to transmit an initial capabilities
- list. It can also appear in tagged responses to LOGIN or
- AUTHENTICATE commands. This makes it unnecessary for a client to
- send a separate CAPABILITY command if it recognizes this response
- code and there was no change to the TLS and/or authentication
- state since it was received.
-
- CLIENTBUG
- The server has detected a client bug. This can accompany any of
- OK, NO, and BAD, depending on what the client bug is.
-
- C: k1 select "/archive/projects/experiment-iv"
- [...]
- S: k1 OK [READ-ONLY] Done
- C: k2 status "/archive/projects/experiment-iv" (messages)
- [...]
- S: k2 OK [CLIENTBUG] Done
-
- CLOSED
- The CLOSED response code has no parameters. A server returns the
- CLOSED response code when the currently selected mailbox is closed
- implicitly using the SELECT or EXAMINE command on another mailbox.
- The CLOSED response code serves as a boundary between responses
- for the previously opened mailbox (which was closed) and the newly
- selected mailbox; all responses before the CLOSED response code
- relate to the mailbox that was closed, and all subsequent
- responses relate to the newly opened mailbox.
-
- There is no need to return the CLOSED response code on completion
- of the CLOSE or the UNSELECT command (or similar), whose purpose
- is to close the currently selected mailbox without opening a new
- one.
-
- CONTACTADMIN
- The user should contact the system administrator or support desk.
-
- C: e login "fred" "foo"
- S: e NO [CONTACTADMIN]
-
- COPYUID
- Followed by the UIDVALIDITY of the destination mailbox, a UID set
- containing the UIDs of the message(s) in the source mailbox that
- were copied to the destination mailbox, followed by another UID
- set containing the UIDs assigned to the copied message(s) in the
- destination mailbox, indicates that the message(s) has been copied
- to the destination mailbox with the stated UID(s).
-
- The source UID set is in the order the message(s) was copied; the
- destination UID set corresponds to the source UID set and is in
- the same order. Neither of the UID sets may contain extraneous
- UIDs or the symbol "*".
-
- UIDs are assigned in strictly ascending order in the mailbox
- (refer to Section 2.3.1.1); note that a range of 12:10 is exactly
- equivalent to 10:12 and refers to the sequence 10,11,12.
-
- This response code is returned in a tagged OK response to the COPY
- or UID COPY command or in the untagged OK response to the MOVE or
- UID MOVE command.
-
- CORRUPTION
- The server discovered that some relevant data (e.g., the mailbox)
- are corrupt. This response code does not include any information
- about what's corrupt, but the server can write that to its
- logfiles.
-
- C: i select "/archive/projects/experiment-iv"
- S: i NO [CORRUPTION] Cannot open mailbox
-
- EXPIRED
- Either authentication succeeded or the server no longer had the
- necessary data; either way, access is no longer permitted using
- that passphrase. The client or user should get a new passphrase.
-
- C: d login "fred" "foo"
- S: d NO [EXPIRED] That password isn't valid any more
-
- EXPUNGEISSUED
- Someone else has issued an EXPUNGE for the same mailbox. The
- client may want to issue NOOP soon. [IMAP-MULTIACCESS] discusses
- this subject in depth.
-
- C: h search from maria@example.com
- S: * ESEARCH (TAG "h") ALL 1:3,5,8,13,21,42
- S: h OK [EXPUNGEISSUED] Search completed
-
- HASCHILDREN
- The mailbox delete operation failed because the mailbox has one or
- more children, and the server doesn't allow deletion of mailboxes
- with children.
-
- C: m356 DELETE Notes
- S: o356 NO [HASCHILDREN] Mailbox "Notes" has children
- that need to be deleted first
-
- INUSE
- An operation has not been carried out because it involves sawing
- off a branch someone else is sitting on. Someone else may be
- holding an exclusive lock needed for this operation, or the
- operation may involve deleting a resource someone else is using,
- typically a mailbox.
-
- The operation may succeed if the client tries again later.
-
- C: g delete "/archive/projects/experiment-iv"
- S: g NO [INUSE] Mailbox in use
-
- LIMIT
- The operation ran up against an implementation limit of some kind,
- such as the number of flags on a single message or the number of
- flags used in a mailbox.
-
- C: m STORE 42 FLAGS f1 f2 f3 f4 f5 ... f250
- S: m NO [LIMIT] At most 32 flags in one mailbox supported
-
- NONEXISTENT
- The operation attempts to delete something that does not exist.
- Similar to ALREADYEXISTS.
-
- C: p RENAME this that
- S: p NO [NONEXISTENT] No such mailbox
-
- NOPERM
- The access control system (e.g., ACL; see [RFC4314]) does not
- permit this user to carry out an operation, such as selecting or
- creating a mailbox.
-
- C: f select "/archive/projects/experiment-iv"
- S: f NO [NOPERM] Access denied
-
- OVERQUOTA
- The user would be over quota after the operation. (The user may
- or may not be over quota already.)
-
- Note that if the server sends OVERQUOTA but doesn't support the
- IMAP QUOTA extension defined by [RFC2087], then there is a quota,
- but the client cannot find out what the quota is.
-
- C: n1 uid copy 1:* oldmail
- S: n1 NO [OVERQUOTA] Sorry
-
- C: n2 uid copy 1:* oldmail
- S: n2 OK [OVERQUOTA] You are now over your soft quota
-
- PARSE
- The human-readable text represents an error in parsing the
- [RFC5322] header or [MIME-IMB] headers of a message in the
- mailbox.
-
- PERMANENTFLAGS
- Followed by a parenthesized list of flags and indicates which of
- the known flags the client can change permanently. Any flags that
- are in the FLAGS untagged response, but not in the PERMANENTFLAGS
- list, cannot be set permanently. The PERMANENTFLAGS list can also
- include the special flag \*, which indicates that it is possible
- to create new keywords by attempting to store those keywords in
- the mailbox. If the client attempts to STORE a flag that is not
- in the PERMANENTFLAGS list, the server will either ignore the
- change or store the state change for the remainder of the current
- session only.
-
- There is no need for a server that included the special flag \* to
- return a new PERMANENTFLAGS response code when a new keyword was
- successfully set on a message upon client request. However, if
- the server has a limit on the number of different keywords that
- can be stored in a mailbox and that limit is reached, the server
- MUST send a new PERMANENTFLAGS response code without the special
- flag \*.
-
- PRIVACYREQUIRED
- The operation is not permitted due to a lack of data
- confidentiality. If TLS is not in use, the client could try
- STARTTLS (see Section 6.2.1) or alternatively reconnect on an
- Implicit TLS port, and then repeat the operation.
-
- C: d login "fred" "foo"
- S: d NO [PRIVACYREQUIRED] Connection offers no privacy
-
- C: d select inbox
- S: d NO [PRIVACYREQUIRED] Connection offers no privacy
-
- READ-ONLY
- The mailbox is selected as read-only, or its access while selected
- has changed from read-write to read-only.
-
- READ-WRITE
- The mailbox is selected as read-write, or its access while
- selected has changed from read-only to read-write.
-
- SERVERBUG
- The server encountered a bug in itself or violated one of its own
- invariants.
-
- C: j select "/archive/projects/experiment-iv"
- S: j NO [SERVERBUG] This should not happen
-
- TRYCREATE
- An APPEND, COPY, or MOVE attempt is failing because the target
- mailbox does not exist (as opposed to some other reason). This is
- a hint to the client that the operation can succeed if the mailbox
- is first created by the CREATE command.
-
- UIDNEXT
- Followed by a decimal number and indicates the next unique
- identifier value. Refer to Section 2.3.1.1 for more information.
-
- UIDNOTSTICKY
- The selected mailbox is supported by a mail store that does not
- support persistent UIDs; that is, UIDVALIDITY will be different
- each time the mailbox is selected. Consequently, APPEND or COPY
- to this mailbox will not return an APPENDUID or COPYUID response
- code.
-
- This response code is returned in an untagged NO response to the
- SELECT command.
-
- Note: servers SHOULD NOT have any UIDNOTSTICKY mail stores.
- This facility exists to support legacy mail stores in which it
- is technically infeasible to support persistent UIDs. This
- should be avoided when designing new mail stores.
-
- UIDVALIDITY
- Followed by a decimal number and indicates the unique identifier
- validity value. Refer to Section 2.3.1.1 for more information.
-
- UNAVAILABLE
- Temporary failure because a subsystem is down. For example, an
- IMAP server that uses a Lightweight Directory Access Protocol
- (LDAP) or Radius server for authentication might use this response
- code when the LDAP/Radius server is down.
-
- C: a LOGIN "fred" "foo"
- S: a NO [UNAVAILABLE] User's backend down for maintenance
-
- UNKNOWN-CTE
- The server does not know how to decode the section's Content-
- Transfer-Encoding.
-
- Client implementations MUST ignore response codes that they do not
- recognize.
-
-7.1.1. OK Response
-
- Contents:
- OPTIONAL response code
- human-readable text
-
- The OK response indicates an information message from the server.
- When tagged, it indicates successful completion of the associated
- command. The human-readable text MAY be presented to the user as an
- information message. The untagged form indicates an information-only
- message; the nature of the information MAY be indicated by a response
- code.
-
- The untagged form is also used as one of three possible greetings at
- connection startup. It indicates that the connection is not yet
- authenticated and that a LOGIN or an AUTHENTICATE command is needed.
-
- Example:
-
- S: * OK IMAP4rev2 server ready
- C: A001 LOGIN fred blurdybloop
- S: * OK [ALERT] System shutdown in 10 minutes
- S: A001 OK LOGIN Completed
-
-7.1.2. NO Response
-
- Contents:
- OPTIONAL response code
- human-readable text
-
- The NO response indicates an operational error message from the
- server. When tagged, it indicates unsuccessful completion of the
- associated command. The untagged form indicates a warning; the
- command can still complete successfully. The human-readable text
- describes the condition.
-
- Example:
-
- C: A222 COPY 1:2 owatagusiam
- S: * NO Disk is 98% full, please delete unnecessary data
- S: A222 OK COPY completed
- C: A223 COPY 3:200 blurdybloop
- S: * NO Disk is 98% full, please delete unnecessary data
- S: * NO Disk is 99% full, please delete unnecessary data
- S: A223 NO COPY failed: disk is full
-
-7.1.3. BAD Response
-
- Contents:
- OPTIONAL response code
- human-readable text
-
- The BAD response indicates an error message from the server. When
- tagged, it reports a protocol-level error in the client's command;
- the tag indicates the command that caused the error. The untagged
- form indicates a protocol-level error for which the associated
- command can not be determined; it can also indicate an internal
- server failure. The human-readable text describes the condition.
-
- Example:
-
- C: ...very long command line...
- S: * BAD Command line too long
- C: ...empty line...
- S: * BAD Empty command line
- C: A443 EXPUNGE
- S: * BAD Disk crash, attempting salvage to a new disk!
- S: * OK Salvage successful, no data lost
- S: A443 OK Expunge completed
-
-7.1.4. PREAUTH Response
-
- Contents:
- OPTIONAL response code
- human-readable text
-
- The PREAUTH response is always untagged and is one of three possible
- greetings at connection startup. It indicates that the connection
- has already been authenticated by external means; thus, no LOGIN/
- AUTHENTICATE command is needed.
-
- Because PREAUTH moves the connection directly to the authenticated
- state, it effectively prevents the client from using the STARTTLS
- command (Section 6.2.1). For this reason, the PREAUTH response
- SHOULD only be returned by servers on connections that are protected
- by TLS (such as on an Implicit TLS port [RFC8314]) or protected
- through other means such as IPsec. Clients that require mandatory
- TLS MUST close the connection after receiving the PREAUTH response on
- a non-protected port.
-
- Example:
-
- S: * PREAUTH IMAP4rev2 server logged in as Smith
-
-7.1.5. BYE Response
-
- Contents:
- OPTIONAL response code
- human-readable text
-
- The BYE response is always untagged and indicates that the server is
- about to close the connection. The human-readable text MAY be
- displayed to the user in a status report by the client. The BYE
- response is sent under one of four conditions:
-
- 1. as part of a normal logout sequence. The server will close the
- connection after sending the tagged OK response to the LOGOUT
- command.
-
- 2. as a panic shutdown announcement. The server closes the
- connection immediately.
-
- 3. as an announcement of an inactivity autologout. The server
- closes the connection immediately.
-
- 4. as one of three possible greetings at connection startup,
- indicating that the server is not willing to accept a connection
- from this client. The server closes the connection immediately.
-
- The difference between a BYE that occurs as part of a normal LOGOUT
- sequence (the first case) and a BYE that occurs because of a failure
- (the other three cases) is that the connection closes immediately in
- the failure case. In all cases, the client SHOULD continue to read
- response data from the server until the connection is closed; this
- will ensure that any pending untagged or completion responses are
- read and processed.
-
- Example:
-
- S: * BYE Autologout; idle for too long
-
-7.2. Server Responses - Server Status
-
- These responses are always untagged. This is how server status data
- are transmitted from the server to the client.
-
-7.2.1. ENABLED Response
-
- Contents: capability listing
-
- The ENABLED response occurs as a result of an ENABLE command. The
- capability listing contains a space-separated listing of capability
- names that the server supports and that were successfully enabled.
- The ENABLED response may contain no capabilities, which means that no
- extensions listed by the client were successfully enabled.
-
- Example:
-
- S: * ENABLED CONDSTORE QRESYNC
-
-7.2.2. CAPABILITY Response
-
- Contents: capability listing
-
- The CAPABILITY response occurs as a result of a CAPABILITY command.
- The capability listing contains a space-separated listing of
- capability names that the server supports. The capability listing
- MUST include the atom "IMAP4rev2", but note that it doesn't have to
- be the first capability listed. The order of capability names has no
- significance.
-
- Client and server implementations MUST implement the capabilities
- "AUTH=PLAIN" (described in [PLAIN]), and MUST implement "STARTTLS"
- and "LOGINDISABLED" on the cleartext port. See the Security
- Considerations (Section 11) for important information related to
- these capabilities.
-
- A capability name that begins with "AUTH=" indicates that the server
- supports that particular authentication mechanism [SASL].
-
- The LOGINDISABLED capability indicates that the LOGIN command is
- disabled, and that the server will respond with a tagged NO response
- to any attempt to use the LOGIN command even if the user name and
- password are valid (their validity will not be checked). An IMAP
- client MUST NOT issue the LOGIN command if the server advertises the
- LOGINDISABLED capability.
-
- Other capability names indicate that the server supports an
- extension, revision, or amendment to the IMAP4rev2 protocol. If
- IMAP4rev1 capability is not advertised, server responses MUST conform
- to this document until the client issues a command that uses an
- additional capability. If both IMAP4rev1 and IMAP4rev2 capabilities
- are advertised, server responses MUST conform to [RFC3501] until the
- client issues a command that uses an additional capability. (For
- example, the client can issue ENABLE IMAP4rev2 to enable
- IMAP4rev2-specific behavior.)
-
- Capability names SHOULD be registered with IANA using the RFC
- Required policy [RFC8126]. A server SHOULD NOT offer unregistered
- capability names.
-
- Client implementations SHOULD NOT require any capability name other
- than "IMAP4rev2", and possibly "STARTTLS" and "LOGINDISABLED" (on a
- cleartext port). Client implementations MUST ignore any unknown
- capability names.
-
- A server MAY send capabilities automatically, by using the CAPABILITY
- response code in the initial PREAUTH or OK responses and by sending
- an updated CAPABILITY response code in the tagged OK response as part
- of a successful authentication. It is unnecessary for a client to
- send a separate CAPABILITY command if it recognizes these automatic
- capabilities and there was no change to the TLS and/or authentication
- state since they were received.
-
- The list of capabilities returned by a server MAY change during the
- connection. In particular, it is quite common for the server to
- change the list of capabilities after successful TLS negotiation
- (STARTTLS command) and/or after successful authentication
- (AUTHENTICATE or LOGIN commands).
-
- Example:
-
- S: * CAPABILITY STARTTLS AUTH=GSSAPI IMAP4rev2 LOGINDISABLED
- XPIG-LATIN
-
- Note that in the above example, XPIG-LATIN is a fictitious capability
- name.
-
-7.3. Server Responses - Mailbox Status
-
- These responses are always untagged. This is how mailbox status data
- are transmitted from the server to the client. Many of these
- responses typically result from a command with the same name.
-
-7.3.1. LIST Response
-
- Contents:
- name attributes
- hierarchy delimiter
- name
- OPTIONAL extension data
-
- The LIST response occurs as a result of a LIST command. It returns a
- single name that matches the LIST specification. There can be
- multiple LIST responses for a single LIST command.
-
- The following base mailbox name attributes are defined:
-
- \NonExistent
- The "\NonExistent" attribute indicates that a mailbox name does
- not refer to an existing mailbox. Note that this attribute is not
- meaningful by itself, as mailbox names that match the canonical
- LIST pattern but don't exist must not be returned unless one of
- the two conditions listed below is also satisfied:
-
- 1. The mailbox name also satisfies the selection criteria (for
- example, it is subscribed and the "SUBSCRIBED" selection
- option has been specified).
-
- 2. "RECURSIVEMATCH" has been specified, and the mailbox name has
- at least one descendant mailbox name that does not match the
- LIST pattern and does match the selection criteria.
-
- In practice, this means that the "\NonExistent" attribute is
- usually returned with one or more of "\Subscribed", "\Remote",
- "\HasChildren", or the CHILDINFO extended data item.
-
- The "\NonExistent" attribute implies "\NoSelect".
-
- \Noinferiors
- It is not possible for any child levels of hierarchy to exist
- under this name; no child levels exist now and none can be created
- in the future.
-
- \Noselect
- It is not possible to use this name as a selectable mailbox.
-
- \HasChildren
- The presence of this attribute indicates that the mailbox has
- child mailboxes. A server SHOULD NOT set this attribute if there
- are child mailboxes and the user does not have permission to
- access any of them. In this case, \HasNoChildren SHOULD be used.
- In many cases, however, a server may not be able to efficiently
- compute whether a user has access to any child mailboxes. Note
- that even though the \HasChildren attribute for a mailbox must be
- correct at the time of processing the mailbox, a client must be
- prepared to deal with a situation when a mailbox is marked with
- the \HasChildren attribute, but no child mailbox appears in the
- response to the LIST command. This might happen, for example, due
- to child mailboxes being deleted or made inaccessible to the user
- (using access control) by another client before the server is able
- to list them.
-
- \HasNoChildren
- The presence of this attribute indicates that the mailbox has NO
- child mailboxes that are accessible to the currently authenticated
- user.
-
- \Marked
- The mailbox has been marked "interesting" by the server; the
- mailbox probably contains messages that have been added since the
- last time the mailbox was selected.
-
- \Unmarked
- The mailbox does not contain any additional messages since the
- last time the mailbox was selected.
-
- \Subscribed
- The mailbox name was subscribed to using the SUBSCRIBE command.
-
- \Remote
- The mailbox is a remote mailbox.
-
- It is an error for the server to return both a \HasChildren and a
- \HasNoChildren attribute in the same LIST response. A client that
- encounters a LIST response with both \HasChildren and \HasNoChildren
- attributes present should act as if both are absent in the LIST
- response.
-
- Note: the \HasNoChildren attribute should not be confused with the
- \NoInferiors attribute, which indicates that no child mailboxes
- exist now and none can be created in the future.
-
- If it is not feasible for the server to determine whether or not the
- mailbox is "interesting", the server SHOULD NOT send either \Marked
- or \Unmarked. The server MUST NOT send more than one of \Marked,
- \Unmarked, and \Noselect for a single mailbox, and it MAY send none
- of these.
-
- In addition to the base mailbox name attributes defined above, an
- IMAP server MAY also include any or all of the following attributes
- that denote "role" (or "special-use") of a mailbox. These attributes
- are included along with base attributes defined above. A given
- mailbox may have none, one, or more than one of these attributes. In
- some cases, a special use is advice to a client about what to put in
- that mailbox. In other cases, it's advice to a client about what to
- expect to find there.
-
- \All
- This mailbox presents all messages in the user's message store.
- Implementations MAY omit some messages, such as, perhaps, those in
- \Trash and \Junk. When this special use is supported, it is
- almost certain to represent a virtual mailbox.
-
- \Archive
- This mailbox is used to archive messages. The meaning of an
- "archival" mailbox is server dependent; typically, it will be used
- to get messages out of the inbox, or otherwise keep them out of
- the user's way, while still making them accessible.
-
- \Drafts
- This mailbox is used to hold draft messages -- typically, messages
- that are being composed but have not yet been sent. In some
- server implementations, this might be a virtual mailbox,
- containing messages from other mailboxes that are marked with the
- "\Draft" message flag. Alternatively, this might just be advice
- that a client put drafts here.
-
- \Flagged
- This mailbox presents all messages marked in some way as
- "important". When this special use is supported, it is likely to
- represent a virtual mailbox collecting messages (from other
- mailboxes) that are marked with the "\Flagged" message flag.
-
- \Junk
- This mailbox is where messages deemed to be junk mail are held.
- Some server implementations might put messages here automatically.
- Alternatively, this might just be advice to a client-side spam
- filter.
-
- \Sent
- This mailbox is used to hold copies of messages that have been
- sent. Some server implementations might put messages here
- automatically. Alternatively, this might just be advice that a
- client save sent messages here.
-
- \Trash
- This mailbox is used to hold messages that have been deleted or
- marked for deletion. In some server implementations, this might
- be a virtual mailbox, containing messages from other mailboxes
- that are marked with the "\Deleted" message flag. Alternatively,
- this might just be advice that a client that chooses not to use
- the IMAP "\Deleted" model should use as its trash location. In
- server implementations that strictly expect the IMAP "\Deleted"
- model, this special use is likely not to be supported.
-
- All special-use attributes are OPTIONAL, and any given server or
- message store may support any combination of the attributes, or none
- at all. In most cases, there will likely be at most one mailbox with
- a given attribute for a given user, but in some server or message
- store implementations, it might be possible for multiple mailboxes to
- have the same special-use attribute.
-
- Special-use attributes are likely to be user specific. User Adam
- might share his \Sent mailbox with user Barb, but that mailbox is
- unlikely to also serve as Barb's \Sent mailbox.
-
- Other mailbox name attributes can be found in the "IMAP Mailbox Name
- Attributes" registry [IMAP-MAILBOX-NAME-ATTRS-REG].
-
- The hierarchy delimiter is a character used to delimit levels of
- hierarchy in a mailbox name. A client can use it to create child
- mailboxes and to search higher or lower levels of naming hierarchy.
- All children of a top-level hierarchy node MUST use the same
- separator character. A NIL hierarchy delimiter means that no
- hierarchy exists; the name is a "flat" name.
-
- The name represents an unambiguous left-to-right hierarchy and MUST
- be valid for use as a reference in LIST command. Unless \Noselect or
- \NonExistent is indicated, the name MUST also be valid as an argument
- for commands, such as SELECT, that accept mailbox names.
-
- The name might be followed by an OPTIONAL series of extended fields,
- a parenthesized list of tagged data (also referred to as an "extended
- data item"). The first element of an extended field is a string,
- which identifies the type of data. [RFC5258] specifies requirements
- on string registration (which are called "tags"; such tags are not to
- be confused with IMAP command tags); in particular, it states that
- "Tags MUST be registered with IANA". This document doesn't change
- that. See Section 9.5 of [RFC5258] for the registration template.
- The server MAY return data in the extended fields that was not
- directly solicited by the client in the corresponding LIST command.
- For example, the client can enable extra extended fields by using
- another IMAP extension that makes use of the extended LIST responses.
- The client MUST ignore all extended fields it doesn't recognize.
-
- Example:
-
- S: * LIST (\Noselect) "/" ~/Mail/foo
-
- Example:
-
- S: * LIST (\Marked) ":" Tables (tablecloth (("edge" "lacy")
- ("color" "red")) Sample "text")
- S: * LIST () ":" Tables:new (tablecloth ("edge" "lacy")
- Sample ("text" "more text"))
-
-7.3.2. NAMESPACE Response
-
- Contents: the prefix and hierarchy delimiter to the server's
- Personal Namespace(s), Other Users' Namespace(s), and
- Shared Namespace(s)
-
- The NAMESPACE response occurs as a result of a NAMESPACE command. It
- contains the prefix and hierarchy delimiter to the server's Personal
- Namespace(s), Other Users' Namespace(s), and Shared Namespace(s) that
- the server wishes to expose. The response will contain a NIL for any
- namespace class that is not available. The Namespace-Response-
- Extensions ABNF non-terminal is defined for extensibility and MAY be
- included in the response.
-
- Example:
-
- S: * NAMESPACE (("" "/")) (("~" "/")) NIL
-
-7.3.3. STATUS Response
-
- Contents:
- name
- status parenthesized list
-
- The STATUS response occurs as a result of a STATUS command. It
- returns the mailbox name that matches the STATUS specification and
- the requested mailbox status information.
-
- Example:
-
- S: * STATUS blurdybloop (MESSAGES 231 UIDNEXT 44292)
-
-7.3.4. ESEARCH Response
-
- Contents: one or more search-return-data pairs
-
- The ESEARCH response occurs as a result of a SEARCH or UID SEARCH
- command.
-
- The ESEARCH response starts with an optional search correlator. If
- it is missing, then the response was not caused by a particular IMAP
- command, whereas if it is present, it contains the tag of the command
- that caused the response to be returned.
-
- The search correlator is followed by an optional UID indicator. If
- this indicator is present, all data in the ESEARCH response refers to
- UIDs; otherwise, all returned data refers to message numbers.
-
- The rest of the ESEARCH response contains one or more search data
- pairs. Each pair starts with a unique return item name, followed by
- a space and the corresponding data. Search data pairs may be
- returned in any order. Unless otherwise specified by an extension,
- any return item name SHOULD appear only once in an ESEARCH response.
-
- This document specifies the following return item names:
-
- MIN
- Returns the lowest message number/UID that satisfies the SEARCH
- criteria.
-
- If the SEARCH results in no matches, the server MUST NOT include
- the MIN return item in the ESEARCH response; however, it still
- MUST send the ESEARCH response.
-
- MAX
- Returns the highest message number/UID that satisfies the SEARCH
- criteria.
-
- If the SEARCH results in no matches, the server MUST NOT include
- the MAX return item in the ESEARCH response; however, it still
- MUST send the ESEARCH response.
-
- ALL
- Returns all message numbers/UIDs that satisfy the SEARCH criteria
- using the sequence-set syntax. Each set MUST be complete; in
- particular, a UID set is returned in an ESEARCH response only when
- each number in the range corresponds to an existing (matching)
- message. The client MUST NOT assume that messages/UIDs will be
- listed in any particular order.
-
- If the SEARCH results in no matches, the server MUST NOT include
- the ALL return item in the ESEARCH response; however, it still
- MUST send the ESEARCH response.
-
- COUNT
- Returns the number of messages that satisfy the SEARCH criteria.
- This return item MUST always be included in the ESEARCH response.
-
- Example:
-
- S: * ESEARCH UID COUNT 17 ALL 4:18,21,28
-
- Example:
-
- S: * ESEARCH (TAG "a567") UID COUNT 17 ALL 4:18,21,28
-
- Example:
-
- S: * ESEARCH COUNT 18 ALL 1:17,21
-
-7.3.5. FLAGS Response
-
- Contents: flag parenthesized list
-
- The FLAGS response occurs as a result of a SELECT or EXAMINE command.
- The flag parenthesized list identifies the flags (at a minimum, the
- system-defined flags) that are applicable for this mailbox. Flags
- other than the system flags can also exist, depending on server
- implementation.
-
- The update from the FLAGS response MUST be remembered by the client.
-
- Example:
-
- S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
-
-7.4. Server Responses - Mailbox Size
-
- These responses are always untagged. This is how changes in the size
- of the mailbox are transmitted from the server to the client.
- Immediately following the "*" token is a number that represents a
- message count.
-
-7.4.1. EXISTS Response
-
- Contents: none
-
- The EXISTS response reports the number of messages in the mailbox.
- This response occurs as a result of a SELECT or EXAMINE command and
- if the size of the mailbox changes (e.g., new messages).
-
- The update from the EXISTS response MUST be remembered by the client.
-
- Example:
-
- S: * 23 EXISTS
-
-7.5. Server Responses - Message Status
-
- These responses are always untagged. This is how message data are
- transmitted from the server to the client, often as a result of a
- command with the same name. Immediately following the "*" token is a
- number that represents a message sequence number.
-
-7.5.1. EXPUNGE Response
-
- Contents: none
-
- The EXPUNGE response reports that the specified message sequence
- number has been permanently removed from the mailbox. The message
- sequence number for each successive message in the mailbox is
- immediately decremented by 1, and this decrement is reflected in
- message sequence numbers in subsequent responses (including other
- untagged EXPUNGE responses).
-
- The EXPUNGE response also decrements the number of messages in the
- mailbox; it is not necessary to send an EXISTS response with the new
- value.
-
- As a result of the immediate decrement rule, message sequence numbers
- that appear in a set of successive EXPUNGE responses depend upon
- whether the messages are removed starting from lower numbers to
- higher numbers, or from higher numbers to lower numbers. For
- example, if the last 5 messages in a 9-message mailbox are expunged,
- a "lower to higher" server will send five untagged EXPUNGE responses
- for message sequence number 5, whereas a "higher to lower" server
- will send successive untagged EXPUNGE responses for message sequence
- numbers 9, 8, 7, 6, and 5.
-
- An EXPUNGE response MUST NOT be sent when no command is in progress,
- nor while responding to a FETCH, STORE, or SEARCH command. This rule
- is necessary to prevent a loss of synchronization of message sequence
- numbers between client and server. A command is not "in progress"
- until the complete command has been received; in particular, a
- command is not "in progress" during the negotiation of command
- continuation.
-
- Note: UID FETCH, UID STORE, and UID SEARCH are different commands
- from FETCH, STORE, and SEARCH. An EXPUNGE response MAY be sent
- during a UID command.
-
- The update from the EXPUNGE response MUST be remembered by the
- client.
-
- Example:
-
- S: * 44 EXPUNGE
-
-7.5.2. FETCH Response
-
- Contents: message data
-
- The FETCH response returns data about a message to the client. The
- data are pairs of data item names, and their values are in
- parentheses. This response occurs as the result of a FETCH or STORE
- command, as well as by a unilateral server decision (e.g., flag
- updates).
-
- The current data items are:
-
- BINARY[]<>
- An or expressing the content of the specified
- section after removing any encoding specified in the corresponding
- Content-Transfer-Encoding header field. If is present,
- it refers to the offset within the DECODED section data.
-
- If the domain of the decoded data is "8bit" and the data does not
- contain the NUL octet, the server SHOULD return the data in a
- instead of a ; this allows the client to
- determine if the "8bit" data contains the NUL octet without having
- to explicitly scan the data stream for NULs.
-
- Messaging clients and servers have been notoriously lax in their
- adherence to the Internet CRLF convention for terminating lines of
- textual data (text/* media types) in Internet protocols. When
- sending data in a BINARY[...] FETCH data item, servers MUST ensure
- that textual line-oriented sections are always transmitted using
- the IMAP CRLF line termination syntax, regardless of the
- underlying storage representation of the data on the server.
-
- If the server does not know how to decode the section's Content-
- Transfer-Encoding, it MUST fail the request and issue a "NO"
- response that contains the "UNKNOWN-CTE" response code.
-
- BINARY.SIZE[]
- The size of the section after removing any encoding specified in
- the corresponding Content-Transfer-Encoding header field. The
- value returned MUST match the size of the or
- that will be returned by the corresponding FETCH BINARY request.
-
- If the server does not know how to decode the section's Content-
- Transfer-Encoding, it MUST fail the request and issue a "NO"
- response that contains the "UNKNOWN-CTE" response code.
-
- BODY
- A form of BODYSTRUCTURE without extension data.
-
- BODY[]<>
- A string expressing the body contents of the specified section.
- The string SHOULD be interpreted by the client according to the
- content transfer encoding, body type, and subtype.
-
- If the origin octet is specified, this string is a substring of
- the entire body contents, starting at that origin octet. This
- means that BODY[]<0> MAY be truncated, but BODY[] is NEVER
- truncated.
-
- Note: The origin octet facility MUST NOT be used by a server in
- a FETCH response unless the client specifically requested it by
- means of a FETCH of a BODY[]<> data item.
-
- 8-bit textual data is permitted if a [CHARSET] identifier is part
- of the body parameter parenthesized list for this section. Note
- that headers (part specifiers HEADER or MIME, or the header
- portion of a MESSAGE/RFC822 or MESSAGE/GLOBAL part) MAY be in UTF-
- 8. Note also that the [RFC5322] delimiting blank line between the
- header and the body is not affected by header-line subsetting; the
- blank line is always included as part of the header data, except
- in the case of a message that has no body and no blank line.
-
- Non-textual data such as binary data MUST be transfer encoded into
- a textual form, such as base64, prior to being sent to the client.
- To derive the original binary data, the client MUST decode the
- transfer-encoded string.
-
- BODYSTRUCTURE
- A parenthesized list that describes the [MIME-IMB] body structure
- of a message. This is computed by the server by parsing the
- [MIME-IMB] header fields, defaulting various fields as necessary.
-
- For example, a simple text message of 48 lines and 2279 octets can
- have a body structure of:
-
- ("TEXT" "PLAIN" ("CHARSET" "US-ASCII") NIL NIL "7BIT" 2279 48)
-
- Multiple parts are indicated by parenthesis nesting. Instead of a
- body type as the first element of the parenthesized list, there is
- a sequence of one or more nested body structures. The second
- element of the parenthesized list is the multipart subtype (mixed,
- digest, parallel, alternative, etc.).
-
- For example, a two-part message consisting of a text and a
- base64-encoded text attachment can have a body structure of:
-
-
- (("TEXT" "PLAIN" ("CHARSET" "US-ASCII") NIL NIL "7BIT" 1152 23)
- ("TEXT" "PLAIN" ("CHARSET" "US-ASCII" "NAME" "cc.diff")
- "<960723163407.20117h@cac.washington.edu>" "Compiler diff"
- "BASE64" 4554 73) "MIXED")
-
- Extension data follows the multipart subtype. Extension data is
- never returned with the BODY fetch but can be returned with a
- BODYSTRUCTURE fetch. Extension data, if present, MUST be in the
- defined order. The extension data of a multipart body part are in
- the following order:
-
- body parameter parenthesized list
- A parenthesized list of attribute/value pairs (e.g., ("foo" "bar"
- "baz" "rag") where "bar" is the value of "foo", and "rag" is the
- value of "baz") as defined in [MIME-IMB]. Servers SHOULD decode
- parameter-value continuations and parameter-value character sets
- as described in [RFC2231], for example, if the message contains
- parameters "baz*0", "baz*1", and "baz*2", the server should decode
- them per [RFC2231], concatenate, and return the resulting value as
- a parameter "baz". Similarly, if the message contains parameters
- "foo*0*" and "foo*1*", the server should decode them per
- [RFC2231], convert to UTF-8, concatenate, and return the resulting
- value as a parameter "foo*".
-
- body disposition
- A parenthesized list, consisting of a disposition type string,
- followed by a parenthesized list of disposition attribute/value
- pairs as defined in [DISPOSITION]. Servers SHOULD decode
- parameter-value continuations as described in [RFC2231].
-
- body language
- A string or parenthesized list giving the body language value as
- defined in [LANGUAGE-TAGS].
-
- body location
- A string giving the body content URI as defined in [LOCATION].
-
- Any following extension data are not yet defined in this version
- of the protocol. Such extension data can consist of zero or more
- NILs, strings, numbers, or potentially nested parenthesized lists
- of such data. Client implementations that do a BODYSTRUCTURE
- fetch MUST be prepared to accept such extension data. Server
- implementations MUST NOT send such extension data until it has
- been defined by a revision of this protocol.
-
- The basic fields of a non-multipart body part are in the following
- order:
-
- body type
- A string giving the content media-type name as defined in
- [MIME-IMB].
-
- body subtype
- A string giving the content subtype name as defined in [MIME-IMB].
-
- body parameter parenthesized list
- A parenthesized list of attribute/value pairs (e.g., ("foo" "bar"
- "baz" "rag") where "bar" is the value of "foo", and "rag" is the
- value of "baz") as defined in [MIME-IMB].
-
- body id
- A string giving the Content-ID header field value as defined in
- Section 7 of [MIME-IMB].
-
- body description
- A string giving the Content-Description header field value as
- defined in Section 8 of [MIME-IMB].
-
- body encoding
- A string giving the content transfer encoding as defined in
- Section 6 of [MIME-IMB].
-
- body size
- A number giving the size of the body in octets. Note that this
- size is the size in its transfer encoding and not the resulting
- size after any decoding.
-
- A body type of type MESSAGE and subtype RFC822 contains,
- immediately after the basic fields, the envelope structure, body
- structure, and size in text lines of the encapsulated message.
-
- A body type of type TEXT contains, immediately after the basic
- fields, the size of the body in text lines. Note that this size
- is the size in its content transfer encoding and not the resulting
- size after any decoding.
-
- Extension data follows the basic fields and the type-specific
- fields listed above. Extension data is never returned with the
- BODY fetch but can be returned with a BODYSTRUCTURE fetch.
- Extension data, if present, MUST be in the defined order.
-
- The extension data of a non-multipart body part are in the
- following order:
-
- body MD5
- A string giving the body MD5 value as defined in [MD5].
-
- body disposition
- A parenthesized list with the same content and function as the
- body disposition for a multipart body part.
-
- body language
- A string or parenthesized list giving the body language value as
- defined in [LANGUAGE-TAGS].
-
- body location
- A string giving the body content URI as defined in [LOCATION].
-
- Any following extension data are not yet defined in this version
- of the protocol and would be as described above under multipart
- extension data.
-
- ENVELOPE
- A parenthesized list that describes the envelope structure of a
- message. This is computed by the server by parsing the [RFC5322]
- header into the component parts, defaulting various fields as
- necessary.
-
- The fields of the envelope structure are in the following order:
- date, subject, from, sender, reply-to, to, cc, bcc, in-reply-to,
- and message-id. The date, subject, in-reply-to, and message-id
- fields are strings. The from, sender, reply-to, to, cc, and bcc
- fields are parenthesized lists of address structures.
-
- An address structure is a parenthesized list that describes an
- electronic mail address. The fields of an address structure are
- in the following order: display name, [SMTP] at-domain-list
- (source route and obs-route ABNF production from [RFC5322]),
- mailbox name (local-part ABNF production from [RFC5322]), and
- hostname.
-
- [RFC5322] group syntax is indicated by a special form of address
- structure in which the hostname field is NIL. If the mailbox name
- field is also NIL, this is an end-of-group marker (semicolon in
- RFC 822 syntax). If the mailbox name field is non-NIL, this is
- the start of a group marker, and the mailbox name field holds the
- group name phrase.
-
- If the Date, Subject, In-Reply-To, and Message-ID header fields
- are absent in the [RFC5322] header, the corresponding member of
- the envelope is NIL; if these header fields are present but empty,
- the corresponding member of the envelope is the empty string.
-
- Note: some servers may return a NIL envelope member in the
- "present but empty" case. Clients SHOULD treat NIL and the
- empty string as identical.
-
- Note: [RFC5322] requires that all messages have a valid Date
- header field. Therefore, for a well-formed message, the date
- member in the envelope cannot be NIL or the empty string.
- However, it can be NIL for a malformed or draft message.
-
- Note: [RFC5322] requires that the In-Reply-To and Message-ID
- header fields, if present, have non-empty content. Therefore,
- for a well-formed message, the in-reply-to and message-id
- members in the envelope cannot be the empty string. However,
- they can still be the empty string for a malformed message.
-
- If the From, To, Cc, and Bcc header fields are absent in the
- [RFC5322] header, or are present but empty, the corresponding
- member of the envelope is NIL.
-
- If the Sender or Reply-To header fields are absent in the
- [RFC5322] header, or are present but empty, the server sets the
- corresponding member of the envelope to be the same value as the
- from member (the client is not expected to know how to do this).
-
- Note: [RFC5322] requires that all messages have a valid From
- header field. Therefore, for a well-formed message, the from,
- sender, and reply-to members in the envelope cannot be NIL.
- However, they can be NIL for a malformed or draft message.
-
- FLAGS
- A parenthesized list of flags that are set for this message.
-
- INTERNALDATE
- A string representing the internal date of the message.
-
- RFC822.SIZE
- A number expressing the size of a message, as described in
- Section 2.3.4.
-
- UID
- A number expressing the unique identifier of the message.
-
- If the server chooses to send unsolicited FETCH responses, they MUST
- include UID FETCH item. Note that this is a new requirement when
- compared to [RFC3501].
-
- Example:
-
- S: * 23 FETCH (FLAGS (\Seen) RFC822.SIZE 44827 UID 447)
-
-7.6. Server Responses - Command Continuation Request
-
- The command continuation request response is indicated by a "+" token
- instead of a tag. This form of response indicates that the server is
- ready to accept the continuation of a command from the client. The
- remainder of this response is a line of text.
-
- This response is used in the AUTHENTICATE command to transmit server
- data to the client and request additional client data. This response
- is also used if an argument to any command is a synchronizing
- literal.
-
- The client is not permitted to send the octets of the synchronizing
- literal unless the server indicates that it is expected. This
- permits the server to process commands and reject errors on a line-
- by-line basis. The remainder of the command, including the CRLF that
- terminates a command, follows the octets of the literal. If there
- are any additional command arguments, the literal octets are followed
- by a space and those arguments.
-
- Example:
-
- C: A001 LOGIN {11}
- S: + Ready for additional command text
- C: FRED FOOBAR {7}
- S: + Ready for additional command text
- C: fat man
- S: A001 OK LOGIN completed
- C: A044 BLURDYBLOOP {102856}
- S: A044 BAD No such command as "BLURDYBLOOP"
-
-8. Sample IMAP4rev2 Connection
-
- The following is a transcript of an IMAP4rev2 connection on a non-TLS
- port. A long line in this sample is broken for editorial clarity.
-
- S: * OK [CAPABILITY STARTTLS AUTH=SCRAM-SHA-256 LOGINDISABLED
- IMAP4rev2] IMAP4rev2 Service Ready
- C: a000 starttls
- S: a000 OK Proceed with TLS negotiation
-
- C: A001 AUTHENTICATE SCRAM-SHA-256
- biwsbj11c2VyLHI9ck9wck5HZndFYmVSV2diTkVrcU8=
- S: + cj1yT3ByTkdmd0ViZVJXZ2JORWtxTyVodllEcFdVYTJSYVRDQWZ1eEZJbGopaE
- 5sRiRrMCxzPVcyMlphSjBTTlk3c29Fc1VFamI2Z1E9PSxpPTQwOTY=
- C: Yz1iaXdzLHI9ck9wck5HZndFYmVSV2diTkVrcU8laHZZRHBXVWEyUmFUQ0FmdXhG
- SWxqKWhObEYkazAscD1kSHpiWmFwV0lrNGpVaE4rVXRlOXl0YWc5empmTUhnc3Ft
- bWl6N0FuZFZRPQ==
- S: + dj02cnJpVFJCaTIzV3BSUi93dHVwK21NaFVaVW4vZEI1bkxUSlJzamw5NUc0
- PQ==
- C:
- S: A001 OK SCRAM-SHA-256 authentication successful
- C: babc ENABLE IMAP4rev2
- S: * ENABLED IMAP4rev2
- S: babc OK Some capabilities enabled
- C: a002 select inbox
- S: * 18 EXISTS
- S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
- S: * OK [UIDVALIDITY 3857529045] UIDs valid
- S: * LIST () "/" INBOX ("OLDNAME" ("inbox"))
- S: a002 OK [READ-WRITE] SELECT completed
- C: a003 fetch 12 full
- S: * 12 FETCH (FLAGS (\Seen) INTERNALDATE
- "17-Jul-1996 02:44:25 -0700" RFC822.SIZE 4286 ENVELOPE (
- "Wed, 17 Jul 1996 02:23:25 -0700 (PDT)"
- "IMAP4rev2 WG mtg summary and minutes"
- (("Terry Gray" NIL "gray" "cac.washington.edu"))
- (("Terry Gray" NIL "gray" "cac.washington.edu"))
- (("Terry Gray" NIL "gray" "cac.washington.edu"))
- ((NIL NIL "imap" "cac.washington.edu"))
- ((NIL NIL "minutes" "CNRI.Reston.VA.US")
- ("John Klensin" NIL "KLENSIN" "MIT.EDU")) NIL NIL
- "")
- BODY ("TEXT" "PLAIN" ("CHARSET" "US-ASCII") NIL NIL "7BIT"
- 3028 92))
- S: a003 OK FETCH completed
- C: a004 fetch 12 body[header]
- S: * 12 FETCH (BODY[HEADER] {342}
- S: Date: Wed, 17 Jul 1996 02:23:25 -0700 (PDT)
- S: From: Terry Gray
- S: Subject: IMAP4rev2 WG mtg summary and minutes
- S: To: imap@cac.washington.edu
- S: cc: minutes@CNRI.Reston.VA.US, John Klensin
- S: Message-Id:
- S: MIME-Version: 1.0
- S: Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
- S:
- S: )
- S: a004 OK FETCH completed
- C: a005 store 12 +flags \deleted
- S: * 12 FETCH (FLAGS (\Seen \Deleted))
- S: a005 OK +FLAGS completed
- C: a006 logout
- S: * BYE IMAP4rev2 server terminating connection
- S: a006 OK LOGOUT completed
-
-9. Formal Syntax
-
- The following syntax specification uses the Augmented Backus-Naur
- Form (ABNF) notation as specified in [ABNF].
-
- In the case of alternative or optional rules in which a later rule
- overlaps an earlier rule, the rule that is listed earlier MUST take
- priority. For example, "\Seen" when parsed as a flag is the \Seen
- flag name and not a flag-extension, even though "\Seen" can be parsed
- as a flag-extension. Some, but not all, instances of this rule are
- noted below.
-
- Note: [ABNF] rules MUST be followed strictly; in particular:
-
- 1. Unless otherwise noted, all alphabetic characters are case
- insensitive. The use of uppercase or lowercase characters to
- define token strings is for editorial clarity only.
- Implementations MUST accept these strings in a case-insensitive
- fashion.
-
- 2. In all cases, SP refers to exactly one space. It is NOT
- permitted to substitute TAB, insert additional spaces, or
- otherwise treat SP as being equivalent to linear whitespace
- (LWSP).
-
- 3. The ASCII NUL character, %x00, MUST NOT be used anywhere, with
- the exception of the OCTET production.
-
- SP =
- CTL =
- CRLF =
- ALPHA =
- DIGIT =
- DQUOTE =
- OCTET =
-
- address = "(" addr-name SP addr-adl SP addr-mailbox SP
- addr-host ")"
-
- addr-adl = nstring
- ; Holds route from [RFC5322] obs-route if
- ; non-NIL
-
- addr-host = nstring
- ; NIL indicates [RFC5322] group syntax.
- ; Otherwise, holds [RFC5322] domain name
-
- addr-mailbox = nstring
- ; NIL indicates end of [RFC5322] group; if
- ; non-NIL and addr-host is NIL, holds
- ; [RFC5322] group name.
- ; Otherwise, holds [RFC5322] local-part
- ; after removing [RFC5322] quoting
-
- addr-name = nstring
- ; If non-NIL, holds phrase from [RFC5322]
- ; mailbox after removing [RFC5322] quoting
-
- append = "APPEND" SP mailbox [SP flag-list] [SP date-time]
- SP literal
-
- append-uid = uniqueid
-
- astring = 1*ASTRING-CHAR / string
-
- ASTRING-CHAR = ATOM-CHAR / resp-specials
-
- atom = 1*ATOM-CHAR
-
- ATOM-CHAR =
-
- atom-specials = "(" / ")" / "{" / SP / CTL / list-wildcards /
- quoted-specials / resp-specials
-
- authenticate = "AUTHENTICATE" SP auth-type [SP initial-resp]
- *(CRLF base64)
-
- auth-type = atom
- ; Authentication mechanism name, as defined by
- ; [SASL], Section 7.1
-
- base64 = *(4base64-char) [base64-terminal]
-
- base64-char = ALPHA / DIGIT / "+" / "/"
- ; Case sensitive
-
- base64-terminal = (2base64-char "==") / (3base64-char "=")
-
- body = "(" (body-type-1part / body-type-mpart) ")"
-
- body-extension = nstring / number / number64 /
- "(" body-extension *(SP body-extension) ")"
- ; Future expansion. Client implementations
- ; MUST accept body-extension fields. Server
- ; implementations MUST NOT generate
- ; body-extension fields except as defined by
- ; future Standard or Standards Track
- ; revisions of this specification.
-
- body-ext-1part = body-fld-md5 [SP body-fld-dsp [SP body-fld-lang
- [SP body-fld-loc *(SP body-extension)]]]
- ; MUST NOT be returned on non-extensible
- ; "BODY" fetch
-
- body-ext-mpart = body-fld-param [SP body-fld-dsp [SP body-fld-lang
- [SP body-fld-loc *(SP body-extension)]]]
- ; MUST NOT be returned on non-extensible
- ; "BODY" fetch
-
- body-fields = body-fld-param SP body-fld-id SP body-fld-desc SP
- body-fld-enc SP body-fld-octets
-
- body-fld-desc = nstring
-
- body-fld-dsp = "(" string SP body-fld-param ")" / nil
-
- body-fld-enc = (DQUOTE ("7BIT" / "8BIT" / "BINARY" / "BASE64"/
- "QUOTED-PRINTABLE") DQUOTE) / string
- ; Content-Transfer-Encoding header field value.
- ; Defaults to "7BIT" (as per RFC 2045)
- ; if not present in the body part.
-
- body-fld-id = nstring
-
- body-fld-lang = nstring / "(" string *(SP string) ")"
-
- body-fld-loc = nstring
-
- body-fld-lines = number64
-
- body-fld-md5 = nstring
-
- body-fld-octets = number
-
- body-fld-param = "(" string SP string *(SP string SP string) ")" /
- nil
-
- body-type-1part = (body-type-basic / body-type-msg / body-type-text)
- [SP body-ext-1part]
-
- body-type-basic = media-basic SP body-fields
- ; MESSAGE subtype MUST NOT be "RFC822" or
- ; "GLOBAL"
-
- body-type-mpart = 1*body SP media-subtype
- [SP body-ext-mpart]
- ; MULTIPART body part
-
- body-type-msg = media-message SP body-fields SP envelope
- SP body SP body-fld-lines
-
- body-type-text = media-text SP body-fields SP body-fld-lines
-
- capability = ("AUTH=" auth-type) / atom
- ; New capabilities SHOULD be
- ; registered with IANA using the
- ; RFC Required policy, i.e., in
- ; a Standards Track, an Experimental,
- ; or an Informational RFC.
-
- capability-data = "CAPABILITY" *(SP capability) SP "IMAP4rev2"
- *(SP capability)
- ; See Section 6.1.1 for information about
- ; required security-related capabilities.
- ; Servers that offer RFC 1730 compatibility MUST
- ; list "IMAP4" as the first capability.
- ; Servers that offer RFC 3501 compatibility MUST
- ; list "IMAP4rev1" as one of the capabilities.
-
- CHAR =
-
- CHAR8 = %x01-ff
- ; any OCTET except NUL, %x00
-
- charset = atom / quoted
-
- childinfo-extended-item = "CHILDINFO" SP "("
- list-select-base-opt-quoted
- *(SP list-select-base-opt-quoted) ")"
- ; Extended data item (mbox-list-extended-item)
- ; returned when the RECURSIVEMATCH
- ; selection option is specified.
- ; Note 1: the CHILDINFO extended data item tag can be
- ; returned with or without surrounding quotes, as per
- ; mbox-list-extended-item-tag production.
- ; Note 2: The selection options are always returned
- ; quoted, unlike their specification in
- ; the extended LIST command.
-
- child-mbox-flag = "\HasChildren" / "\HasNoChildren"
- ; attributes for the CHILDREN return option, at most
- ; one possible per LIST response
-
- command = tag SP (command-any / command-auth /
- command-nonauth / command-select) CRLF
- ; Modal based on state
-
- command-any = "CAPABILITY" / "LOGOUT" / "NOOP"
- ; Valid in all states
-
- command-auth = append / create / delete / enable / examine /
- list / namespace-command / rename /
- select / status / subscribe / unsubscribe /
- idle
- ; Valid only in Authenticated or Selected state
-
- command-nonauth = login / authenticate / "STARTTLS"
- ; Valid only when in Not Authenticated state
-
- command-select = "CLOSE" / "UNSELECT" / "EXPUNGE" / copy /
- move / fetch / store / search / uid
- ; Valid only when in Selected state
-
- continue-req = "+" SP (resp-text / base64) CRLF
-
- copy = "COPY" SP sequence-set SP mailbox
-
- create = "CREATE" SP mailbox
- ; Use of INBOX gives a NO error
-
- date = date-text / DQUOTE date-text DQUOTE
-
- date-day = 1*2DIGIT
- ; Day of month
-
- date-day-fixed = (SP DIGIT) / 2DIGIT
- ; Fixed-format version of date-day
-
- date-month = "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" /
- "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec"
-
- date-text = date-day "-" date-month "-" date-year
-
- date-year = 4DIGIT
-
- date-time = DQUOTE date-day-fixed "-" date-month "-" date-year
- SP time SP zone DQUOTE
-
- delete = "DELETE" SP mailbox
- ; Use of INBOX gives a NO error
-
- digit-nz = %x31-39
- ; 1-9
-
- eitem-standard-tag = atom
- ; a tag for LIST extended data item defined in a Standard
- ; Track or Experimental RFC.
-
- eitem-vendor-tag = vendor-token "-" atom
- ; a vendor-specific tag for LIST extended data item
-
- enable = "ENABLE" 1*(SP capability)
-
- enable-data = "ENABLED" *(SP capability)
-
- envelope = "(" env-date SP env-subject SP env-from SP
- env-sender SP env-reply-to SP env-to SP env-cc SP
- env-bcc SP env-in-reply-to SP env-message-id ")"
-
- env-bcc = "(" 1*address ")" / nil
-
- env-cc = "(" 1*address ")" / nil
-
- env-date = nstring
-
- env-from = "(" 1*address ")" / nil
-
- env-in-reply-to = nstring
-
- env-message-id = nstring
-
- env-reply-to = "(" 1*address ")" / nil
-
- env-sender = "(" 1*address ")" / nil
-
- env-subject = nstring
-
- env-to = "(" 1*address ")" / nil
-
- esearch-response = "ESEARCH" [search-correlator] [SP "UID"]
- *(SP search-return-data)
- ; ESEARCH response replaces SEARCH response
- ; from IMAP4rev1.
-
- examine = "EXAMINE" SP mailbox
-
- fetch = "FETCH" SP sequence-set SP (
- "ALL" / "FULL" / "FAST" /
- fetch-att / "(" fetch-att *(SP fetch-att) ")")
-
- fetch-att = "ENVELOPE" / "FLAGS" / "INTERNALDATE" /
- "RFC822.SIZE" /
- "BODY" ["STRUCTURE"] / "UID" /
- "BODY" section [partial] /
- "BODY.PEEK" section [partial] /
- "BINARY" [".PEEK"] section-binary [partial] /
- "BINARY.SIZE" section-binary
-
- flag = "\Answered" / "\Flagged" / "\Deleted" /
- "\Seen" / "\Draft" / flag-keyword / flag-extension
- ; Does not include "\Recent"
-
- flag-extension = "\" atom
- ; Future expansion. Client implementations
- ; MUST accept flag-extension flags. Server
- ; implementations MUST NOT generate
- ; flag-extension flags except as defined by
- ; a future Standard or Standards Track
- ; revisions of this specification.
- ; "\Recent" was defined in RFC 3501
- ; and is now deprecated.
-
- flag-fetch = flag / obsolete-flag-recent
-
- flag-keyword = "$MDNSent" / "$Forwarded" / "$Junk" /
- "$NotJunk" / "$Phishing" / atom
-
- flag-list = "(" [flag *(SP flag)] ")"
-
- flag-perm = flag / "\*"
-
- greeting = "*" SP (resp-cond-auth / resp-cond-bye) CRLF
-
- header-fld-name = astring
-
- header-list = "(" header-fld-name *(SP header-fld-name) ")"
-
- idle = "IDLE" CRLF "DONE"
-
- initial-resp = (base64 / "=")
- ; "initial response" defined in
- ; Section 4 of [SASL]
-
- list = "LIST" [SP list-select-opts] SP
- mailbox SP mbox-or-pat
- [SP list-return-opts]
-
-
- list-mailbox = 1*list-char / string
-
- list-char = ATOM-CHAR / list-wildcards / resp-specials
-
- list-return-opt = return-option
- ; Note that return-option is the ABNF
- ; non-terminal used by RFC 5258
-
- list-return-opts = "RETURN" SP
- "(" [list-return-opt *(SP list-return-opt)] ")"
- ; list return options, e.g., CHILDREN
-
- list-select-base-opt = "SUBSCRIBED" / option-extension
- ; options that can be used by themselves
-
- list-select-base-opt-quoted = DQUOTE list-select-base-opt DQUOTE
-
- list-select-independent-opt = "REMOTE" / option-extension
- ; options that do not syntactically interact with
- ; other options
-
- list-select-mod-opt = "RECURSIVEMATCH" / option-extension
- ; options that require a list-select-base-opt
- ; to also be present
-
- list-select-opt = list-select-base-opt / list-select-independent-opt
- / list-select-mod-opt
-
- list-select-opts = "(" [
- (*(list-select-opt SP) list-select-base-opt
- *(SP list-select-opt))
- / (list-select-independent-opt
- *(SP list-select-independent-opt))
- ] ")"
- ; Any number of options may be in any order.
- ; If a list-select-mod-opt appears, then a
- ; list-select-base-opt must also appear.
- ; This allows these:
- ; ()
- ; (REMOTE)
- ; (SUBSCRIBED)
- ; (SUBSCRIBED REMOTE)
- ; (SUBSCRIBED RECURSIVEMATCH)
- ; (SUBSCRIBED REMOTE RECURSIVEMATCH)
- ; But does NOT allow these:
- ; (RECURSIVEMATCH)
- ; (REMOTE RECURSIVEMATCH)
-
- list-wildcards = "%" / "*"
-
- literal = "{" number64 ["+"] "}" CRLF *CHAR8
- ; represents the number of CHAR8s.
- ; A non-synchronizing literal is distinguished
- ; from a synchronizing literal by the presence of
- ; "+" before the closing "}".
- ; Non-synchronizing literals are not allowed when
- ; sent from server to the client.
-
- literal8 = "~{" number64 "}" CRLF *OCTET
- ; represents the number of OCTETs
- ; in the response string.
-
- login = "LOGIN" SP userid SP password
-
- mailbox = "INBOX" / astring
- ; INBOX is case insensitive. All case variants
- ; of INBOX (e.g., "iNbOx") MUST be interpreted as
- ; INBOX, not as an astring. An astring that
- ; consists of the case-insensitive sequence
- ; "I" "N" "B" "O" "X" is considered
- ; to be an INBOX and not an astring.
- ; Refer to Section 5.1 for further
- ; semantic details of mailbox names.
-
- mailbox-data = "FLAGS" SP flag-list / "LIST" SP mailbox-list /
- esearch-response /
- "STATUS" SP mailbox SP "(" [status-att-list] ")" /
- number SP "EXISTS" / namespace-response /
- obsolete-search-response /
- obsolete-recent-response
- ; obsolete-search-response and
- ; obsolete-recent-response can only be returned
- ; by servers that support both IMAPrev1
- ; and IMAPrev2.
-
- mailbox-list = "(" [mbx-list-flags] ")" SP
- (DQUOTE QUOTED-CHAR DQUOTE / nil) SP mailbox
- [SP mbox-list-extended]
- ; This is the list information pointed to by the ABNF
- ; item "mailbox-data", which is defined above
-
- mbox-list-extended = "(" [mbox-list-extended-item
- *(SP mbox-list-extended-item)] ")"
-
- mbox-list-extended-item = mbox-list-extended-item-tag SP
- tagged-ext-val
-
- mbox-list-extended-item-tag = astring
- ; The content MUST conform to either
- ; "eitem-vendor-tag" or "eitem-standard-tag"
- ; ABNF productions.
-
- mbox-or-pat = list-mailbox / patterns
-
- mbx-list-flags = *(mbx-list-oflag SP) mbx-list-sflag
- *(SP mbx-list-oflag) /
- mbx-list-oflag *(SP mbx-list-oflag)
-
- mbx-list-oflag = "\Noinferiors" / child-mbox-flag /
- "\Subscribed" / "\Remote" / flag-extension
- ; Other flags; multiple from this list are
- ; possible per LIST response, but each flag
- ; can only appear once per LIST response
-
- mbx-list-sflag = "\NonExistent" / "\Noselect" / "\Marked" /
- "\Unmarked"
- ; Selectability flags; only one per LIST response
-
- media-basic = ((DQUOTE ("APPLICATION" / "AUDIO" / "IMAGE" /
- "FONT" / "MESSAGE" / "MODEL" / "VIDEO" ) DQUOTE)
- / string)
- SP media-subtype
- ; FONT defined in [RFC8081].
- ; MODEL defined in [RFC2077].
- ; Other top-level media types
- ; are defined in [MIME-IMT].
-
- media-message = DQUOTE "MESSAGE" DQUOTE SP
- DQUOTE ("RFC822" / "GLOBAL") DQUOTE
- ; Defined in [MIME-IMT]
-
- media-subtype = string
- ; Defined in [MIME-IMT]
-
- media-text = DQUOTE "TEXT" DQUOTE SP media-subtype
- ; Defined in [MIME-IMT]
-
- message-data = nz-number SP ("EXPUNGE" / ("FETCH" SP msg-att))
-
- move = "MOVE" SP sequence-set SP mailbox
-
- msg-att = "(" (msg-att-dynamic / msg-att-static)
- *(SP (msg-att-dynamic / msg-att-static)) ")"
-
- msg-att-dynamic = "FLAGS" SP "(" [flag-fetch *(SP flag-fetch)] ")"
- ; MAY change for a message
-
- msg-att-static = "ENVELOPE" SP envelope /
- "INTERNALDATE" SP date-time /
- "RFC822.SIZE" SP number64 /
- "BODY" ["STRUCTURE"] SP body /
- "BODY" section ["<" number ">"] SP nstring /
- "BINARY" section-binary SP (nstring / literal8) /
- "BINARY.SIZE" section-binary SP number /
- "UID" SP uniqueid
- ; MUST NOT change for a message
-
- name-component = 1*UTF8-CHAR
- ; MUST NOT contain ".", "/", "%", or "*"
-
- namespace = nil / "(" 1*namespace-descr ")"
-
- namespace-command = "NAMESPACE"
-
- namespace-descr = "(" string SP
- (DQUOTE QUOTED-CHAR DQUOTE / nil)
- [namespace-response-extensions] ")"
-
- namespace-response-extensions = *namespace-response-extension
-
- namespace-response-extension = SP string SP
- "(" string *(SP string) ")"
-
- namespace-response = "NAMESPACE" SP namespace
- SP namespace SP namespace
- ; The first Namespace is the Personal Namespace(s).
- ; The second Namespace is the Other Users'
- ; Namespace(s).
- ; The third Namespace is the Shared Namespace(s).
-
- nil = "NIL"
-
- nstring = string / nil
-
- number = 1*DIGIT
- ; Unsigned 32-bit integer
- ; (0 <= n < 4,294,967,296)
-
- number64 = 1*DIGIT
- ; Unsigned 63-bit integer
- ; (0 <= n <= 9,223,372,036,854,775,807)
-
- nz-number = digit-nz *DIGIT
- ; Non-zero unsigned 32-bit integer
- ; (0 < n < 4,294,967,296)
-
- nz-number64 = digit-nz *DIGIT
- ; Unsigned 63-bit integer
- ; (0 < n <= 9,223,372,036,854,775,807)
-
- obsolete-flag-recent = "\Recent"
-
- obsolete-recent-response = number SP "RECENT"
-
- obsolete-search-response = "SEARCH" *(SP nz-number)
-
- oldname-extended-item = "OLDNAME" SP "(" mailbox ")"
- ; Extended data item (mbox-list-extended-item)
- ; returned in a LIST response when a mailbox is
- ; renamed or deleted. Also returned when
- ; the server canonicalized the provided mailbox
- ; name.
- ; Note 1: the OLDNAME tag can be returned
- ; with or without surrounding quotes, as per
- ; mbox-list-extended-item-tag production.
-
- option-extension = (option-standard-tag / option-vendor-tag)
- [SP option-value]
-
- option-standard-tag = atom
- ; an option defined in a Standards Track or
- ; Experimental RFC
-
- option-val-comp = astring /
- option-val-comp *(SP option-val-comp) /
- "(" option-val-comp ")"
-
- option-value = "(" option-val-comp ")"
-
- option-vendor-tag = vendor-token "-" atom
- ; a vendor-specific option, non-standard
-
- partial-range = number64 ["." nz-number64]
- ; Copied from RFC 5092 (IMAP URL)
- ; and updated to support 64-bit sizes.
-
- partial = "<" number64 "." nz-number64 ">"
- ; Partial FETCH request. 0-based offset of
- ; the first octet, followed by the number of
- ; octets in the fragment.
-
- password = astring
-
- patterns = "(" list-mailbox ")"
- ; [RFC5258] supports multiple patterns,
- ; but this document only requires one
- ; to be supported.
- ; If the server is also implementing
- ; [RFC5258], the "patterns" syntax from
- ; that document must be followed.
-
- quoted = DQUOTE *QUOTED-CHAR DQUOTE
-
- QUOTED-CHAR = /
- "\" quoted-specials / UTF8-2 / UTF8-3 / UTF8-4
-
- quoted-specials = DQUOTE / "\"
-
- rename = "RENAME" SP mailbox SP mailbox
- ; Use of INBOX as a destination gives a NO error
-
- response = *(continue-req / response-data) response-done
-
- response-data = "*" SP (resp-cond-state / resp-cond-bye /
- mailbox-data / message-data / capability-data /
- enable-data) CRLF
-
- response-done = response-tagged / response-fatal
-
- response-fatal = "*" SP resp-cond-bye CRLF
- ; Server closes connection immediately
-
- response-tagged = tag SP resp-cond-state CRLF
-
- resp-code-apnd = "APPENDUID" SP nz-number SP append-uid
-
- resp-code-copy = "COPYUID" SP nz-number SP uid-set SP uid-set
-
- resp-cond-auth = ("OK" / "PREAUTH") SP resp-text
- ; Authentication condition
-
- resp-cond-bye = "BYE" SP resp-text
-
- resp-cond-state = ("OK" / "NO" / "BAD") SP resp-text
- ; Status condition
-
- resp-specials = "]"
-
- resp-text = ["[" resp-text-code "]" SP] [text]
-
- resp-text-code = "ALERT" /
- "BADCHARSET" [SP "(" charset *(SP charset) ")" ] /
- capability-data / "PARSE" /
- "PERMANENTFLAGS" SP
- "(" [flag-perm *(SP flag-perm)] ")" /
- "READ-ONLY" / "READ-WRITE" / "TRYCREATE" /
- "UIDNEXT" SP nz-number /
- "UIDVALIDITY" SP nz-number /
- resp-code-apnd / resp-code-copy / "UIDNOTSTICKY" /
- "UNAVAILABLE" / "AUTHENTICATIONFAILED" /
- "AUTHORIZATIONFAILED" / "EXPIRED" /
- "PRIVACYREQUIRED" / "CONTACTADMIN" / "NOPERM" /
- "INUSE" / "EXPUNGEISSUED" / "CORRUPTION" /
- "SERVERBUG" / "CLIENTBUG" / "CANNOT" /
- "LIMIT" / "OVERQUOTA" / "ALREADYEXISTS" /
- "NONEXISTENT" / "NOTSAVED" / "HASCHILDREN" /
- "CLOSED" /
- "UNKNOWN-CTE" /
- atom [SP 1*]
-
- return-option = "SUBSCRIBED" / "CHILDREN" / status-option /
- option-extension
-
- search = "SEARCH" [search-return-opts]
- SP search-program
-
- search-correlator = SP "(" "TAG" SP tag-string ")"
-
- search-key = "ALL" / "ANSWERED" / "BCC" SP astring /
- "BEFORE" SP date / "BODY" SP astring /
- "CC" SP astring / "DELETED" / "FLAGGED" /
- "FROM" SP astring / "KEYWORD" SP flag-keyword /
- "ON" SP date / "SEEN" /
- "SINCE" SP date / "SUBJECT" SP astring /
- "TEXT" SP astring / "TO" SP astring /
- "UNANSWERED" / "UNDELETED" / "UNFLAGGED" /
- "UNKEYWORD" SP flag-keyword / "UNSEEN" /
- ; Above this line were in [IMAP2]
- "DRAFT" / "HEADER" SP header-fld-name SP astring /
- "LARGER" SP number64 / "NOT" SP search-key /
- "OR" SP search-key SP search-key /
- "SENTBEFORE" SP date / "SENTON" SP date /
- "SENTSINCE" SP date / "SMALLER" SP number64 /
- "UID" SP sequence-set / "UNDRAFT" / sequence-set /
- "(" search-key *(SP search-key) ")"
-
- search-modifier-name = tagged-ext-label
-
- search-mod-params = tagged-ext-val
- ; This non-terminal shows recommended syntax
- ; for future extensions.
-
- search-program = ["CHARSET" SP charset SP]
- search-key *(SP search-key)
- ; CHARSET argument to SEARCH MUST be
- ; registered with IANA.
-
- search-ret-data-ext = search-modifier-name SP search-return-value
- ; Note that not every SEARCH return option
- ; is required to have the corresponding
- ; ESEARCH return data.
-
- search-return-data = "MIN" SP nz-number /
- "MAX" SP nz-number /
- "ALL" SP sequence-set /
- "COUNT" SP number /
- search-ret-data-ext
- ; All return data items conform to
- ; search-ret-data-ext syntax.
- ; Note that "$" marker is not allowed
- ; after the ALL return data item.
-
- search-return-opts = SP "RETURN" SP "(" [search-return-opt
- *(SP search-return-opt)] ")"
-
- search-return-opt = "MIN" / "MAX" / "ALL" / "COUNT" /
- "SAVE" /
- search-ret-opt-ext
- ; conforms to generic search-ret-opt-ext
- ; syntax
-
- search-ret-opt-ext = search-modifier-name [SP search-mod-params]
-
- search-return-value = tagged-ext-val
- ; Data for the returned search option.
- ; A single "nz-number"/"number"/"number64" value
- ; can be returned as an atom (i.e., without
- ; quoting). A sequence-set can be returned
- ; as an atom as well.
-
- section = "[" [section-spec] "]"
-
- section-binary = "[" [section-part] "]"
-
- section-msgtext = "HEADER" /
- "HEADER.FIELDS" [".NOT"] SP header-list /
- "TEXT"
- ; top-level or MESSAGE/RFC822 or
- ; MESSAGE/GLOBAL part
-
- section-part = nz-number *("." nz-number)
- ; body part reference.
- ; Allows for accessing nested body parts.
-
- section-spec = section-msgtext / (section-part ["." section-text])
-
- section-text = section-msgtext / "MIME"
- ; text other than actual body part (headers,
- ; etc.)
-
- select = "SELECT" SP mailbox
-
- seq-number = nz-number / "*"
- ; message sequence number (COPY, FETCH, STORE
- ; commands) or unique identifier (UID COPY,
- ; UID FETCH, UID STORE commands).
- ; * represents the largest number in use. In
- ; the case of message sequence numbers, it is
- ; the number of messages in a non-empty mailbox.
- ; In the case of unique identifiers, it is the
- ; unique identifier of the last message in the
- ; mailbox or, if the mailbox is empty, the
- ; mailbox's current UIDNEXT value.
- ; The server should respond with a tagged BAD
- ; response to a command that uses a message
- ; sequence number greater than the number of
- ; messages in the selected mailbox. This
- ; includes "*" if the selected mailbox is empty.
-
- seq-range = seq-number ":" seq-number
- ; two seq-number values and all values between
- ; these two regardless of order.
- ; Example: 2:4 and 4:2 are equivalent and
- ; indicate values 2, 3, and 4.
- ; Example: a unique identifier sequence range of
- ; 3291:* includes the UID of the last message in
- ; the mailbox, even if that value is less than
- ; 3291.
-
- sequence-set = (seq-number / seq-range) ["," sequence-set]
- ; set of seq-number values, regardless of order.
- ; Servers MAY coalesce overlaps and/or execute
- ; the sequence in any order.
- ; Example: a message sequence number set of
- ; 2,4:7,9,12:* for a mailbox with 15 messages is
- ; equivalent to 2,4,5,6,7,9,12,13,14,15
- ; Example: a message sequence number set of
- ; *:4,5:7 for a mailbox with 10 messages is
- ; equivalent to 10,9,8,7,6,5,4,5,6,7 and MAY
- ; be reordered and overlap coalesced to be
- ; 4,5,6,7,8,9,10.
-
- sequence-set =/ seq-last-command
- ; Allow for "result of the last command"
- ; indicator.
-
- seq-last-command = "$"
-
- status = "STATUS" SP mailbox SP
- "(" status-att *(SP status-att) ")"
-
- status-att = "MESSAGES" / "UIDNEXT" / "UIDVALIDITY" /
- "UNSEEN" / "DELETED" / "SIZE"
-
- status-att-val = ("MESSAGES" SP number) /
- ("UIDNEXT" SP nz-number) /
- ("UIDVALIDITY" SP nz-number) /
- ("UNSEEN" SP number) /
- ("DELETED" SP number) /
- ("SIZE" SP number64)
- ; Extensions to the STATUS responses
- ; should extend this production.
- ; Extensions should use the generic
- ; syntax defined by tagged-ext.
-
- status-att-list = status-att-val *(SP status-att-val)
-
- status-option = "STATUS" SP "(" status-att *(SP status-att) ")"
- ; This ABNF production complies with
- ; syntax.
-
- store = "STORE" SP sequence-set SP store-att-flags
-
- store-att-flags = (["+" / "-"] "FLAGS" [".SILENT"]) SP
- (flag-list / (flag *(SP flag)))
-
- string = quoted / literal
-
- subscribe = "SUBSCRIBE" SP mailbox
-
- tag = 1*
-
- tag-string = astring
- ; represented as
-
- tagged-ext-label = tagged-label-fchar *tagged-label-char
- ; Is a valid RFC 3501 "atom".
-
- tagged-label-fchar = ALPHA / "-" / "_" / "."
-
- tagged-label-char = tagged-label-fchar / DIGIT / ":"
-
- tagged-ext-comp = astring /
- tagged-ext-comp *(SP tagged-ext-comp) /
- "(" tagged-ext-comp ")"
- ; Extensions that follow this general
- ; syntax should use nstring instead of
- ; astring when appropriate in the context
- ; of the extension.
- ; Note that a message set or a "number"
- ; can always be represented as an "atom".
- ; A URL should be represented as
- ; a "quoted" string.
-
- tagged-ext-simple = sequence-set / number / number64
-
- tagged-ext-val = tagged-ext-simple /
- "(" [tagged-ext-comp] ")"
-
- text = 1*(TEXT-CHAR / UTF8-2 / UTF8-3 / UTF8-4)
- ; Non-ASCII text can only be returned
- ; after ENABLE IMAP4rev2 command
-
- TEXT-CHAR =
-
- time = 2DIGIT ":" 2DIGIT ":" 2DIGIT
- ; Hours minutes seconds
-
- uid = "UID" SP
- (copy / move / fetch / search / store /
- uid-expunge)
- ; Unique identifiers used instead of message
- ; sequence numbers
-
- uid-expunge = "EXPUNGE" SP sequence-set
- ; Unique identifiers used instead of message
- ; sequence numbers
-
- uid-set = (uniqueid / uid-range) *("," uid-set)
-
- uid-range = (uniqueid ":" uniqueid)
- ; two uniqueid values and all values
- ; between these two regardless of order.
- ; Example: 2:4 and 4:2 are equivalent.
-
- uniqueid = nz-number
- ; Strictly ascending
-
- unsubscribe = "UNSUBSCRIBE" SP mailbox
-
- userid = astring
-
- UTF8-CHAR =
-
- UTF8-2 =
-
- UTF8-3 =
-
- UTF8-4 =
-
- vendor-token = "vendor." name-component
- ; Definition copied from RFC 2244.
- ; MUST be registered with IANA
-
- zone = ("+" / "-") 4DIGIT
- ; Signed four-digit value of hhmm representing
- ; hours and minutes east of Greenwich (that is,
- ; the amount that the given time differs from
- ; Universal Time). Subtracting the timezone
- ; from the given time will give the UT form.
- ; The Universal Time zone is "+0000".
diff --git a/lib/servers/mail/mailbox/README.md b/lib/servers/mail/mailbox/README.md
deleted file mode 100644
index a8c0c898..00000000
--- a/lib/servers/mail/mailbox/README.md
+++ /dev/null
@@ -1,82 +0,0 @@
-# Mailbox Module
-
-A V language implementation of a mailbox system that provides core functionality for managing email messages. This module is designed to be used as part of an email server implementation, providing the fundamental storage and retrieval operations for email messages.
-
-## Core Components
-
-### Message
-
-```v
-pub struct Message {
-pub mut:
- uid u32 // Unique identifier for the message
- subject string
- body string
- flags []string // e.g.: ["\Seen", "\Flagged"]
- internal_date time.Time // Message arrival time
-}
-```
-
-### MailServer
-
-The MailServer struct provides the following public methods:
-
-#### Account Management
-- `account_create(username string, description string, emails []string) !` - Creates a new user account
-- `account_delete(username string) !` - Deletes a user account
-- `account_list() []string` - Lists all usernames
-- `account_find_by_email(email string) !string` - Finds account by email address
-
-#### Mailbox Management
-- `mailbox_list(username string) ![]string` - Lists all mailboxes for a user
-- `mailbox_create(username string, mailbox string) !` - Creates a new mailbox for a user
-- `mailbox_delete(username string, mailbox string) !` - Deletes a mailbox for a user
-
-#### Message Management
-- `message_list(username string, mailbox string) ![]Message` - Returns all messages in the mailbox
-- `message_get(username string, mailbox string, uid u32) !Message` - Gets a message by its UID
-- `message_delete(username string, mailbox string, uid u32) !` - Deletes a message by its UID
-- `message_set(username string, mailbox string, uid u32, msg Message) !` - Sets/updates a message with the given UID
-- `message_find(username string, mailbox string, args FindArgs) ![]Message` - Finds messages matching the given criteria
-- `message_len(username string, mailbox string) !int` - Returns the number of messages in a mailbox
-
-## Usage Example
-
-```v
-// Create a new mail server
-mut server := new()
-
-// Create a user account
-server.account_create('user1', 'First User', ['user1@example.com'])!
-
-// Create a new mailbox
-server.mailbox_create('user1', 'Important')!
-
-// Add a message
-msg := Message{
- uid: 1
- subject: 'Hello'
- body: 'World'
- flags: ['\\Seen']
-}
-server.message_set('user1', 'Important', msg.uid, msg)!
-
-// List messages
-messages := server.message_list('user1', 'Important')!
-
-// Find messages
-results := server.message_find('user1', 'Important', FindArgs{
- subject: 'Hello'
- content: 'World'
- flags: ['\\Seen']
-})!
-
-// Delete a message
-server.message_delete('user1', 'Important', 1)!
-```
-
-## Notes
-
-- Each message has a unique identifier (UID) that remains constant
-- Messages can be flagged with standard IMAP flags (e.g. \\Seen, \\Flagged)
-- Search operations support filtering by subject, content, and flags
diff --git a/lib/servers/mail/mailbox/demodata.v b/lib/servers/mail/mailbox/demodata.v
deleted file mode 100644
index edb98a1a..00000000
--- a/lib/servers/mail/mailbox/demodata.v
+++ /dev/null
@@ -1,45 +0,0 @@
-module mailbox
-
-import time
-
-// Creates demo data with 5 user accounts, each having 2 mailboxes and 20 messages
-pub fn (mut self MailServer) demodata() ! {
- usernames := ['user1', 'user2', 'user3', 'user4', 'user5']
- names := ['First User', 'Second User', 'Third User', 'Fourth User', 'Fifth User']
-
- for i, username in usernames {
- // Create primary and alternate email addresses
- primary_email := '${username}@example.com'
- alt_email := '${username}.alt@example.com'
- emails := [primary_email, alt_email]
-
- // Create user account (INBOX is created by default)
- self.account_create(username, names[i], emails)!
-
- // Create second mailbox
- self.mailbox_create(username, 'Sent')!
-
- // Add 10 messages to each mailbox
- for j in 0 .. 10 {
- // Add message to INBOX
- inbox_msg := Message{
- uid: u32(j + 1) // UIDs start at 1
- subject: 'Inbox Message ${j + 1}'
- body: 'This is inbox message ${j + 1} for ${username}'
- flags: if j % 2 == 0 { ['\\Seen'] } else { [] }
- internal_date: time.now()
- }
- self.message_set(username, 'INBOX', inbox_msg.uid, inbox_msg)!
-
- // Add message to Sent
- sent_msg := Message{
- uid: u32(j + 1) // UIDs start at 1
- subject: 'Sent Message ${j + 1}'
- body: 'This is sent message ${j + 1} from ${username}'
- flags: ['\\Seen']
- internal_date: time.now()
- }
- self.message_set(username, 'Sent', sent_msg.uid, sent_msg)!
- }
- }
-}
diff --git a/lib/servers/mail/mailbox/demodata_test.v b/lib/servers/mail/mailbox/demodata_test.v
deleted file mode 100644
index accf3cb6..00000000
--- a/lib/servers/mail/mailbox/demodata_test.v
+++ /dev/null
@@ -1,61 +0,0 @@
-module mailbox
-
-fn test_demodata() {
- mut server := new()
- server.demodata()!
-
- // Test user accounts
- usernames := ['user1', 'user2', 'user3', 'user4', 'user5']
- names := ['First User', 'Second User', 'Third User', 'Fourth User', 'Fifth User']
-
- for i, username in usernames {
- // Verify user exists by checking email
- primary_email := '${username}@example.com'
- found_username := server.account_find_by_email(primary_email) or { panic(err) }
- assert found_username == username
-
- alt_email := '${username}.alt@example.com'
- found_username_alt := server.account_find_by_email(alt_email) or { panic(err) }
- assert found_username_alt == username
-
- // Verify mailboxes exist
- mailboxes := server.mailbox_list(username) or { panic(err) }
- assert mailboxes.len == 2
- assert 'INBOX' in mailboxes
- assert 'Sent' in mailboxes
-
- // Verify INBOX messages
- inbox_messages := server.message_list(username, 'INBOX') or { panic(err) }
- assert inbox_messages.len == 10
-
- // Check specific properties of first and last INBOX messages
- first_msg := server.message_get(username, 'INBOX', u32(1)) or { panic(err) }
- assert first_msg.subject == 'Inbox Message 1'
- assert first_msg.body == 'This is inbox message 1 for ${username}'
- assert first_msg.flags == ['\\Seen']
-
- last_msg := server.message_get(username, 'INBOX', u32(10)) or { panic(err) }
- assert last_msg.subject == 'Inbox Message 10'
- assert last_msg.body == 'This is inbox message 10 for ${username}'
- assert last_msg.flags == if 9 % 2 == 0 {
- ['\\Seen']
- } else {
- []
- }
-
- // Verify Sent messages
- sent_messages := server.message_list(username, 'Sent') or { panic(err) }
- assert sent_messages.len == 10
-
- // Check specific properties of first and last Sent messages
- first_sent := server.message_get(username, 'Sent', u32(1)) or { panic(err) }
- assert first_sent.subject == 'Sent Message 1'
- assert first_sent.body == 'This is sent message 1 from ${username}'
- assert first_sent.flags == ['\\Seen']
-
- last_sent := server.message_get(username, 'Sent', u32(10)) or { panic(err) }
- assert last_sent.subject == 'Sent Message 10'
- assert last_sent.body == 'This is sent message 10 from ${username}'
- assert last_sent.flags == ['\\Seen']
- }
-}
diff --git a/lib/servers/mail/mailbox/factory.v b/lib/servers/mail/mailbox/factory.v
deleted file mode 100644
index 681433ac..00000000
--- a/lib/servers/mail/mailbox/factory.v
+++ /dev/null
@@ -1,15 +0,0 @@
-module mailbox
-
-pub fn new() &MailServer {
- return &MailServer{
- accounts: map[string]&UserAccount{}
- }
-}
-
-pub fn new_with_demo_data() !&MailServer {
- mut s := &MailServer{
- accounts: map[string]&UserAccount{}
- }
- s.demodata()!
- return s
-}
diff --git a/lib/servers/mail/mailbox/mailbox.v b/lib/servers/mail/mailbox/mailbox.v
deleted file mode 100644
index e834cacf..00000000
--- a/lib/servers/mail/mailbox/mailbox.v
+++ /dev/null
@@ -1,106 +0,0 @@
-module mailbox
-
-// Represents a mailbox holding messages.
-@[heap]
-struct Mailbox {
-mut:
- name string
- messages []Message
- next_uid u32 // Next unique identifier to be assigned
- uid_validity u32 // Unique identifier validity value
- read_only bool // Whether mailbox is read-only
-}
-
-// Returns all messages in the mailbox
-fn (mut self Mailbox) list() ![]Message {
- return self.messages
-}
-
-// Gets a message by its UID
-fn (mut self Mailbox) get(uid u32) !Message {
- for msg in self.messages {
- if msg.uid == uid {
- return msg
- }
- }
- return error('Message with UID ${uid} not found')
-}
-
-// Deletes a message by its UID
-fn (mut self Mailbox) delete(uid u32) ! {
- for i, msg in self.messages {
- if msg.uid == uid {
- self.messages.delete(i)
- return
- }
- }
- return error('Message with UID ${uid} not found')
-}
-
-// Sets/updates a message with the given UID
-fn (mut self Mailbox) set(uid u32, msg Message) ! {
- if self.read_only {
- return error('Mailbox is read-only')
- }
-
- mut found := false
- for i, existing in self.messages {
- if existing.uid == uid {
- self.messages[i] = msg
- found = true
- break
- }
- }
-
- if !found {
- // Add as new message if UID doesn't exist
- self.messages << msg
- }
-}
-
-@[params]
-pub struct FindArgs {
-pub mut:
- subject string
- content string
- flags []string
-}
-
-// Finds messages matching the given criteria
-fn (mut self Mailbox) find(args FindArgs) ![]Message {
- mut results := []Message{}
-
- for msg in self.messages {
- mut matches := true
-
- // Check subject if specified
- if args.subject != '' && !msg.subject.contains(args.subject) {
- matches = false
- }
-
- // Check content if specified
- if matches && args.content != '' && !msg.body.contains(args.content) {
- matches = false
- }
-
- // Check all specified flags are present
- if matches && args.flags.len > 0 {
- for flag in args.flags {
- if flag !in msg.flags {
- matches = false
- break
- }
- }
- }
-
- if matches {
- results << msg
- }
- }
-
- return results
-}
-
-fn (mut self Mailbox) len() int {
- return self.messages.len
-}
diff --git a/lib/servers/mail/mailbox/mailbox_test.v b/lib/servers/mail/mailbox/mailbox_test.v
deleted file mode 100644
index 62e59b93..00000000
--- a/lib/servers/mail/mailbox/mailbox_test.v
+++ /dev/null
@@ -1,142 +0,0 @@
-module mailbox
-
-import time
-
-fn test_mailbox_basic_operations() {
- mut mb := Mailbox{
- name: 'INBOX'
- uid_validity: 1234
- }
-
- // Test empty mailbox
- msgs := mb.list() or { panic(err) }
- assert msgs.len == 0
-
- // Test adding a message
- msg1 := Message{
- uid: 1
- subject: 'Test email'
- body: 'Hello world'
- flags: ['\\Seen']
- internal_date: time.now()
- }
- mb.set(1, msg1) or { panic(err) }
-
- // Test listing messages
- msgs2 := mb.list() or { panic(err) }
- assert msgs2.len == 1
- assert msgs2[0].subject == 'Test email'
-
- // Test getting message by UID
- found := mb.get(1) or { panic(err) }
- assert found.uid == 1
- assert found.subject == 'Test email'
- assert found.body == 'Hello world'
- assert found.flags == ['\\Seen']
-}
-
-fn test_mailbox_delete() {
- mut mb := Mailbox{
- name: 'INBOX'
- uid_validity: 1234
- }
-
- // Add two messages
- msg1 := Message{
- uid: 1
- subject: 'First email'
- body: 'Content 1'
- }
- msg2 := Message{
- uid: 2
- subject: 'Second email'
- body: 'Content 2'
- }
- mb.set(1, msg1) or { panic(err) }
- mb.set(2, msg2) or { panic(err) }
-
- // Delete first message
- mb.delete(1) or { panic(err) }
-
- // Verify only second message remains
- msgs := mb.list() or { panic(err) }
- assert msgs.len == 1
- assert msgs[0].uid == 2
- assert msgs[0].subject == 'Second email'
-
- // Test deleting non-existent message
- if _ := mb.delete(999) {
- panic('Expected error when deleting non-existent message')
- }
-}
-
-fn test_mailbox_find() {
- mut mb := Mailbox{
- name: 'INBOX'
- uid_validity: 1234
- }
-
- // Add test messages
- msg1 := Message{
- uid: 1
- subject: 'Important meeting'
- body: 'Meeting at 2 PM'
- flags: ['\\Seen', '\\Flagged']
- }
- msg2 := Message{
- uid: 2
- subject: 'Hello friend'
- body: 'How are you?'
- flags: ['\\Seen']
- }
- msg3 := Message{
- uid: 3
- subject: 'Another meeting'
- body: 'Team sync at 3 PM'
- flags: ['\\Draft']
- }
-
- mb.set(1, msg1) or { panic(err) }
- mb.set(2, msg2) or { panic(err) }
- mb.set(3, msg3) or { panic(err) }
-
- // Test finding by subject
- found_subject := mb.find(FindArgs{ subject: 'meeting' }) or { panic(err) }
- assert found_subject.len == 2
-
- // Test finding by content
- found_content := mb.find(FindArgs{ content: 'PM' }) or { panic(err) }
- assert found_content.len == 2
-
- // Test finding by flags
- found_flags := mb.find(FindArgs{ flags: ['\\Seen', '\\Flagged'] }) or { panic(err) }
- assert found_flags.len == 1
- assert found_flags[0].uid == 1
-
- // Test finding with multiple criteria
- found_multi := mb.find(FindArgs{
- subject: 'meeting'
- flags: ['\\Draft']
- }) or { panic(err) }
- assert found_multi.len == 1
- assert found_multi[0].uid == 3
-}
-
-fn test_readonly_mailbox() {
- mut mb := Mailbox{
- name: 'INBOX'
- uid_validity: 1234
- read_only: true
- }
-
- msg := Message{
- uid: 1
- subject: 'Test email'
- body: 'Hello world'
- }
-
- // Attempt to modify read-only mailbox should fail
- if _ := mb.set(1, msg) {
- panic('Expected error when modifying read-only mailbox')
- }
-}
diff --git a/lib/servers/mail/mailbox/mailserver_pub.v b/lib/servers/mail/mailbox/mailserver_pub.v
deleted file mode 100644
index 15716797..00000000
--- a/lib/servers/mail/mailbox/mailserver_pub.v
+++ /dev/null
@@ -1,126 +0,0 @@
-module mailbox
-
-// Represents the mail server that manages user accounts
-@[heap]
-pub struct MailServer {
-mut:
- accounts map[string]&UserAccount // Map of username to user account
-}
-
-// Creates a new user account
-pub fn (mut self MailServer) account_create(username string, description string, emails []string) ! {
- if username in self.accounts {
- return error('User ${username} already exists')
- }
-
- // Verify emails are unique across all accounts
- for _, account in self.accounts {
- for email in emails {
- if email in account.emails {
- return error('Email ${email} is already registered to another account')
- }
- }
- }
-
- mut account := &UserAccount{
- name: username
- description: description
- emails: emails.clone()
- mailboxes: map[string]&Mailbox{}
- }
- self.accounts[username] = account
-
- // Create default INBOX mailbox
- account.create_mailbox('INBOX') or { return err }
-}
-
-// Deletes a user account
-pub fn (mut self MailServer) account_delete(username string) ! {
- if username !in self.accounts {
- return error('User ${username} not found')
- }
- self.accounts.delete(username)
-}
-
-// Lists all usernames
-pub fn (self MailServer) account_list() []string {
- return self.accounts.keys()
-}
-
-// Finds account by email address
-pub fn (mut self MailServer) account_find_by_email(email string) !string {
- for _, account in self.accounts {
- if email in account.emails {
- return account.name
- }
- }
- return error('No account found with email ${email}')
-}
-
-// Gets a user account by username (internal only)
-fn (mut self MailServer) account_get(username string) !&UserAccount {
- if account := self.accounts[username] {
- return account
- }
- return error('User ${username} not found')
-}
-
-// Lists all mailboxes for a user
-pub fn (mut self MailServer) mailbox_list(username string) ![]string {
- account := self.account_get(username)!
- return account.list_mailboxes()
-}
-
-// Creates a new mailbox for a user
-pub fn (mut self MailServer) mailbox_create(username string, mailbox string) ! {
- mut account := self.account_get(username)!
- account.create_mailbox(mailbox)!
-}
-
-// Deletes a mailbox for a user
-pub fn (mut self MailServer) mailbox_delete(username string, mailbox string) ! {
- mut account := self.account_get(username)!
- account.delete_mailbox(mailbox)!
-}
-
-// Returns all messages in the mailbox
-pub fn (mut self MailServer) message_list(username string, mailbox string) ![]Message {
- mut account := self.account_get(username)!
- mut mb := account.get_mailbox(mailbox)!
- return mb.list()
-}
-
-// Gets a message by its UID
-pub fn (mut self MailServer) message_get(username string, mailbox string, uid u32) !Message {
- mut account := self.account_get(username)!
- mut mb := account.get_mailbox(mailbox)!
- return mb.get(uid)
-}
-
-// Deletes a message by its UID
-pub fn (mut self MailServer) message_delete(username string, mailbox string, uid u32) ! {
- mut account := self.account_get(username)!
- mut mb := account.get_mailbox(mailbox)!
- mb.delete(uid)!
-}
-
-// Sets/updates a message with the given UID
-pub fn (mut self MailServer) message_set(username string, mailbox string, uid u32, msg Message) ! {
- mut account := self.account_get(username)!
- mut mb := account.get_mailbox(mailbox)!
- mb.set(uid, msg)!
-}
-
-// Finds messages matching the given criteria
-pub fn (mut self MailServer) message_find(username string, mailbox string, args FindArgs) ![]Message {
- mut account := self.account_get(username)!
- mut mb := account.get_mailbox(mailbox)!
- return mb.find(args)
-}
-
-// Returns the number of messages in a mailbox
-pub fn (mut self MailServer) message_len(username string, mailbox string) !int {
- mut account := self.account_get(username)!
- mut mb := account.get_mailbox(mailbox)!
- return mb.len()
-}
diff --git a/lib/servers/mail/mailbox/message.v b/lib/servers/mail/mailbox/message.v
deleted file mode 100644
index 797c7347..00000000
--- a/lib/servers/mail/mailbox/message.v
+++ /dev/null
@@ -1,14 +0,0 @@
-module mailbox
-
-import time
-
-// Represents an email message.
-@[heap]
-pub struct Message {
-pub mut:
- uid u32 // Unique identifier for the message
- subject string
- body string
- flags []string // e.g.: ["\\Seen", "\\Flagged"]
- internal_date time.Time // Message arrival time
-}
diff --git a/lib/servers/mail/mailbox/useraccount.v b/lib/servers/mail/mailbox/useraccount.v
deleted file mode 100644
index bd619518..00000000
--- a/lib/servers/mail/mailbox/useraccount.v
+++ /dev/null
@@ -1,48 +0,0 @@
-module mailbox
-
-import time
-
-// Represents a user account in the mail server
-@[heap]
-struct UserAccount {
-mut:
- name string
- description string
- emails []string
- mailboxes map[string]&Mailbox // Map of mailbox name to mailbox instance
-}
-
-// Creates a new mailbox for the user account
-fn (mut self UserAccount) create_mailbox(name string) !&Mailbox {
- if name in self.mailboxes {
- return error('Mailbox ${name} already exists')
- }
-
- mb := &Mailbox{
- name: name
- uid_validity: u32(time.now().unix())
- }
- self.mailboxes[name] = mb
- return mb
-}
-
-// Gets a mailbox by name
-fn (mut self UserAccount) get_mailbox(name string) !&Mailbox {
- if mailbox := self.mailboxes[name] {
- return mailbox
- }
- return error('Mailbox ${name} not found')
-}
-
-// Deletes a mailbox by name
-fn (mut self UserAccount) delete_mailbox(name string) ! {
- if name !in self.mailboxes {
- return error('Mailbox ${name} not found')
- }
- self.mailboxes.delete(name)
-}
-
-// Lists all mailboxes for the user
-fn (self UserAccount) list_mailboxes() []string {
- return self.mailboxes.keys()
-}
diff --git a/lib/servers/mail/mailbox/useraccount_test.v b/lib/servers/mail/mailbox/useraccount_test.v
deleted file mode 100644
index 943fabc4..00000000
--- a/lib/servers/mail/mailbox/useraccount_test.v
+++ /dev/null
@@ -1,140 +0,0 @@
-module mailbox
-
-import time
-
-fn test_user_account_mailboxes() {
- mut account := UserAccount{
- name: 'testuser'
- description: 'Test User'
- emails: ['test@example.com']
- }
-
- // Test creating mailboxes
- inbox := account.create_mailbox('INBOX') or { panic(err) }
- assert inbox.name == 'INBOX'
-
- sent := account.create_mailbox('Sent') or { panic(err) }
- assert sent.name == 'Sent'
-
- // Test duplicate mailbox creation
- if _ := account.create_mailbox('INBOX') {
- panic('Expected error when creating duplicate mailbox')
- }
-
- // Test listing mailboxes
- boxes := account.list_mailboxes()
- assert boxes.len == 2
- assert 'INBOX' in boxes
- assert 'Sent' in boxes
-
- // Test getting mailbox
- found := account.get_mailbox('INBOX') or { panic(err) }
- assert found.name == 'INBOX'
-
- // Test getting non-existent mailbox
- if _ := account.get_mailbox('NonExistent') {
- panic('Expected error when getting non-existent mailbox')
- }
-
- // Test deleting mailbox
- account.delete_mailbox('Sent') or { panic(err) }
- boxes_after_delete := account.list_mailboxes()
- assert boxes_after_delete.len == 1
- assert 'Sent' !in boxes_after_delete
-}
-
-fn test_mail_server_accounts() {
- mut server := MailServer{}
-
- // Test creating accounts
- server.account_create('user1', 'First User', ['user1@example.com', 'user1.alt@example.com']) or {
- panic(err)
- }
- mut account1 := server.account_get('user1') or { panic(err) }
- assert account1.name == 'user1'
- assert account1.emails.len == 2
-
- // Verify INBOX was created automatically
- mut inbox := account1.get_mailbox('INBOX') or { panic(err) }
- assert inbox.name == 'INBOX'
-
- // Test creating account with duplicate username
- if _ := server.account_create('user1', 'Duplicate User', ['other@example.com']) {
- panic('Expected error when creating account with duplicate username')
- }
-
- // Test creating account with duplicate email
- if _ := server.account_create('user2', 'Second User', ['user1@example.com']) {
- panic('Expected error when creating account with duplicate email')
- }
-
- // Test creating another valid account
- server.account_create('user2', 'Second User', ['user2@example.com']) or { panic(err) }
- mut account2 := server.account_get('user2') or { panic(err) }
- assert account2.name == 'user2'
-
- // Test listing accounts
- accounts := server.account_list()
- assert accounts.len == 2
- assert 'user1' in accounts
- assert 'user2' in accounts
-
- // Test getting account
- mut found := server.account_get('user1') or { panic(err) }
- assert found.name == 'user1'
- assert found.emails == ['user1@example.com', 'user1.alt@example.com']
-
- // Test getting non-existent account
- if _ := server.account_get('nonexistent') {
- panic('Expected error when getting non-existent account')
- }
-
- // Test finding account by email
- found_by_email := server.account_find_by_email('user1.alt@example.com') or { panic(err) }
- assert found_by_email == 'user1'
-
- // Test finding non-existent email
- if _ := server.account_find_by_email('nonexistent@example.com') {
- panic('Expected error when finding non-existent email')
- }
-
- // Test deleting account
- server.account_delete('user2') or { panic(err) }
- accounts_after_delete := server.account_list()
- assert accounts_after_delete.len == 1
- assert 'user2' !in accounts_after_delete
-}
-
-fn test_end_to_end() {
- mut server := MailServer{}
-
- // Create account
- server.account_create('testuser', 'Test User', ['test@example.com']) or { panic(err) }
- mut account := server.account_get('testuser') or { panic(err) }
-
- // Get INBOX and add a message
- mut inbox := account.get_mailbox('INBOX') or { panic(err) }
- msg := Message{
- uid: 1
- subject: 'Test message'
- body: 'Hello world'
- flags: ['\\Seen']
- }
- inbox.set(1, msg) or { panic(err) }
-
- // Create Archives mailbox
- mut archives := account.create_mailbox('Archives') or { panic(err) }
-
- // Verify mailboxes through server lookup
- mut found_account := server.account_get('testuser') or { panic(err) }
- mailboxes := found_account.list_mailboxes()
- assert mailboxes.len == 2
- assert 'INBOX' in mailboxes
- assert 'Archives' in mailboxes
-
- // Verify message in INBOX
- mut found_inbox := found_account.get_mailbox('INBOX') or { panic(err) }
- msgs := found_inbox.list() or { panic(err) }
- assert msgs.len == 1
- assert msgs[0].subject == 'Test message'
-}
diff --git a/lib/servers/mail/server/factory.v b/lib/servers/mail/server/factory.v
deleted file mode 100644
index 738a9357..00000000
--- a/lib/servers/mail/server/factory.v
+++ /dev/null
@@ -1,23 +0,0 @@
-module server
-
-import freeflowuniverse.herolib.servers.mail.mailbox
-import freeflowuniverse.herolib.servers.mail.imap
-import freeflowuniverse.herolib.servers.mail.smtp
-
-pub fn start_demo() ! {
- // Create the server and initialize an example INBOX.
-
- mut mailboxserver := mailbox.new_with_demo_data()!
-
- // Use new from imap module and use mailboxserver as input
- mut imap_server := imap.new(mailboxserver)!
- mut smtp_server := smtp.new(mailboxserver)!
-
- imap_server.start()!
- smtp_server.start()!
-
- println('servers started.')
-
- for {
- }
-}
diff --git a/lib/servers/mail/server/readme.md b/lib/servers/mail/server/readme.md
deleted file mode 100644
index 0e168873..00000000
--- a/lib/servers/mail/server/readme.md
+++ /dev/null
@@ -1,12 +0,0 @@
-## hero mail server
-
-see examples/servers/imap_example.vsh for example
-
-```v
-#!/usr/bin/env -S v -n -w -cg -gc none -cc tcc -d use_openssl -enable-globals run
-
-import freeflowuniverse.herolib.servers.mail.server
-
-// Start the IMAP server on port 143
-server.start_demo() !
-```
\ No newline at end of file
diff --git a/lib/servers/mail/smtp/README.md b/lib/servers/mail/smtp/README.md
deleted file mode 100644
index 25db8972..00000000
--- a/lib/servers/mail/smtp/README.md
+++ /dev/null
@@ -1,121 +0,0 @@
-# SMTP Server
-
-A simple SMTP server implementation in V that integrates with the mailbox module for message storage.
-
-## Features
-
-- SMTP server implementation with persistent storage via mailbox module
-- Support for basic SMTP commands (HELO/EHLO, MAIL FROM, RCPT TO, DATA)
-- Authentication support (PLAIN and LOGIN methods)
-- TLS capability advertising
-- Concurrent client handling
-- Integration with mailbox module for message storage
-
-## Usage
-
-The server can be started with a simple function call:
-
-```v
-import freeflowuniverse.herolib.servers.mail.smtp
-import freeflowuniverse.herolib.servers.mail.mailbox
-
-fn main() {
- // Create the mail server
- mut mailserver := mailbox.new_mail_server()
-
- // Create the SMTP server wrapping the mail server
- mut smtp_server := smtp.new(mailserver)!
-
- // Start the SMTP server on port 25
- smtp_server.start()!
-}
-```
-
-Save this to `example.v` and run with:
-
-```bash
-v run example.v
-```
-
-The server will start listening on port 25 (default SMTP port).
-
-## Testing with SMTP Client
-
-You can test the server using any SMTP client. Here's an example using the `telnet` command:
-
-```bash
-# Connect to server
-telnet localhost 25
-
-# Example session:
-EHLO example.com
-MAIL FROM:
-RCPT TO:
-DATA
-Subject: Test Message
-Hello World!
-.
-QUIT
-```
-
-## Implementation Details
-
-The server consists of two main components:
-
-1. **Mailbox Module** (`mailbox/`): Core mail functionality
- - User account management
- - Message storage and retrieval
- - Mailbox operations
-
-2. **SMTP Server** (`smtp/`): SMTP protocol implementation
- - TCP connection handling and session management
- - SMTP command processing
- - Maps SMTP operations to mailbox module functionality
- - Concurrent client support
-
-## Supported Commands
-
-- `HELO/EHLO`: Initial greeting and capability negotiation
-- `MAIL FROM`: Specify sender address
-- `RCPT TO`: Specify recipient address(es)
-- `DATA`: Input email content
-- `RSET`: Reset session state
-- `QUIT`: End session
-- `AUTH`: Authentication (PLAIN/LOGIN methods)
-- `NOOP`: No operation
-
-## Example Session
-
-```
-S: 220 SMTP server ready
-C: EHLO example.com
-S: 250-example.com
-S: 250-8BITMIME
-S: 250-PIPELINING
-S: 250-STARTTLS
-S: 250-AUTH PLAIN LOGIN
-S: 250 HELP
-C: MAIL FROM:
-S: 250 OK
-C: RCPT TO:
-S: 250 OK
-C: DATA
-S: 354 Start mail input; end with .
-C: Subject: Test Email
-C:
-C: This is a test message.
-C: .
-S: 250 OK
-C: QUIT
-S: 221 Goodbye
-```
-
-## Notes
-
-- The server runs on port 25, which typically requires root privileges. Make sure you have the necessary permissions.
-- This is a basic implementation for demonstration purposes. For production use, consider adding:
- - TLS encryption implementation
- - Full message parsing and MIME support
- - More robust authentication
- - Rate limiting and spam protection
- - Extended SMTP features (SIZE, DSN, etc.)
diff --git a/lib/servers/mail/smtp/factory.v b/lib/servers/mail/smtp/factory.v
deleted file mode 100644
index 21c42ae8..00000000
--- a/lib/servers/mail/smtp/factory.v
+++ /dev/null
@@ -1,10 +0,0 @@
-module smtp
-
-import freeflowuniverse.herolib.servers.mail.mailbox
-
-pub fn new(mailboxserver &mailbox.MailServer) !SMTPServer {
- mut server := SMTPServer{
- mailboxserver: mailboxserver
- }
- return server
-}
diff --git a/lib/servers/mail/smtp/model.v b/lib/servers/mail/smtp/model.v
deleted file mode 100644
index 25d04170..00000000
--- a/lib/servers/mail/smtp/model.v
+++ /dev/null
@@ -1,81 +0,0 @@
-module smtp
-
-import net
-import io
-import freeflowuniverse.herolib.servers.mail.mailbox
-
-// SMTPServer wraps the mailbox server to provide SMTP functionality
-@[heap]
-pub struct SMTPServer {
-pub mut:
- mailboxserver &mailbox.MailServer
-}
-
-// Session represents an active SMTP client connection
-pub struct Session {
-pub mut:
- server &SMTPServer
- conn net.TcpConn
- reader &io.BufferedReader
- tls_active bool
- helo_domain string
- mail_from string
- rcpt_to []string
- data_mode bool
- authenticated bool
- username string
-}
-
-// State represents the current state of the SMTP session
-enum State {
- initial
- helo
- mail
- rcpt
- data
- quit
-}
-
-// Response codes as defined in RFC 5321
-// Positive completion replies
-pub const reply_ready = 220 // Service ready
-
-pub const reply_goodbye = 221 // Service closing transmission channel
-
-pub const reply_ok = 250 // Requested mail action okay, completed
-
-pub const reply_start_mail = 354 // Start mail input
-
-// Permanent negative completion replies
-pub const reply_syntax_error = 500 // Syntax error, command unrecognized
-
-pub const reply_syntax_error_params = 501 // Syntax error in parameters
-
-pub const reply_not_implemented = 502 // Command not implemented
-
-pub const reply_bad_sequence = 503 // Bad sequence of commands
-
-pub const reply_auth_required = 530 // Authentication required
-
-pub const reply_mailbox_unavailable = 550 // Mailbox unavailable
-
-pub const reply_user_not_local = 551 // User not local
-
-pub const reply_storage_exceeded = 552 // Requested mail action aborted: exceeded storage allocation
-
-pub const reply_name_not_allowed = 553 // Requested action not taken: mailbox name not allowed
-
-pub const reply_transaction_failed = 554 // Transaction failed
-
-// send_response sends a formatted SMTP response to the client
-pub fn (mut self Session) send_response(code int, message string) ! {
- response := '${code} ${message}\r\n'
- self.conn.write(response.bytes())!
-}
-
-// reset_session resets the session state for a new mail transaction
-pub fn (mut self Session) reset_session() {
- self.mail_from = ''
- self.rcpt_to = []string{}
- self.data_mode = false
-}
diff --git a/lib/servers/mail/smtp/server.v b/lib/servers/mail/smtp/server.v
deleted file mode 100644
index 121f92c8..00000000
--- a/lib/servers/mail/smtp/server.v
+++ /dev/null
@@ -1,321 +0,0 @@
-module smtp
-
-import net
-import io
-import freeflowuniverse.herolib.ui.console
-import freeflowuniverse.herolib.servers.mail.mailbox
-import time
-
-// start starts the SMTP server on port 25 and accepts client connections
-pub fn (mut server SMTPServer) start() ! {
- spawn daemon(mut server)
-}
-
-fn daemon(mut server SMTPServer) ! {
- addr := '0.0.0.0:25'
- mut listener := net.listen_tcp(.ip, addr, dualstack: true) or {
- return error('Failed to listen on ${addr}: ${err}')
- }
- println('SMTP Server listening on ${addr}')
-
- for {
- mut conn := listener.accept() or {
- eprintln('Failed to accept connection: ${err}')
- continue
- }
-
- conn.set_read_timeout(30 * time.second)
- conn.set_write_timeout(30 * time.second)
-
- spawn handle_connection(mut conn, mut server)
- }
-}
-
-// handle_connection processes commands from a connected SMTP client
-fn handle_connection(mut conn net.TcpConn, mut server SMTPServer) ! {
- defer {
- conn.close() or { panic(err) }
- }
-
- mut reader := io.new_buffered_reader(reader: conn)
- defer {
- unsafe {
- reader.free()
- }
- }
-
- mut session := Session{
- server: &server
- conn: conn
- reader: reader
- tls_active: false
- authenticated: false
- }
-
- client_addr := conn.peer_addr()!
- console.print_debug('> new SMTP client: ${client_addr}')
-
- // Send initial greeting
- session.send_response(reply_ready, 'SMTP server ready')!
-
- for {
- // Read a line (command) from the client
- line := reader.read_line() or {
- match err.msg() {
- 'closed' {
- console.print_debug('Client disconnected normally')
- return error('client disconnected')
- }
- 'EOF' {
- console.print_debug('Client connection ended (EOF)')
- return error('connection ended')
- }
- else {
- eprintln('Connection read error: ${err}')
- return error('connection error: ${err}')
- }
- }
- }
-
- console.print_debug('< ${line}')
- trimmed := line.trim_space()
- if trimmed.len == 0 {
- continue
- }
-
- if session.data_mode {
- handle_data_content(mut session, trimmed)!
- continue
- }
-
- // Parse command and parameters
- parts := trimmed.split(' ')
- cmd := parts[0].to_upper()
-
- match cmd {
- 'HELO', 'EHLO' {
- handle_helo(mut session, parts)!
- }
- 'MAIL' {
- handle_mail(mut session, parts)!
- }
- 'RCPT' {
- handle_rcpt(mut session, parts)!
- }
- 'DATA' {
- handle_data(mut session)!
- }
- 'RSET' {
- handle_rset(mut session)!
- }
- 'QUIT' {
- handle_quit(mut session)!
- return
- }
- 'AUTH' {
- handle_auth(mut session, parts)!
- }
- 'NOOP' {
- session.send_response(reply_ok, 'OK')!
- }
- else {
- session.send_response(reply_syntax_error, 'Command not recognized')!
- }
- }
- }
-}
-
-// handle_helo processes HELO/EHLO commands
-fn handle_helo(mut session Session, parts []string) ! {
- if parts.len < 2 {
- session.send_response(reply_syntax_error_params, 'Missing domain parameter')!
- return
- }
-
- session.helo_domain = parts[1]
- mut capabilities := ['8BITMIME', 'PIPELINING']
-
- if !session.tls_active {
- capabilities << 'STARTTLS'
- }
- if !session.authenticated {
- capabilities << 'AUTH PLAIN LOGIN'
- }
-
- if parts[0].to_upper() == 'EHLO' {
- // Send multi-line EHLO response
- session.send_response(reply_ok, '${session.helo_domain}')!
- for cap in capabilities {
- session.conn.write('250-${cap}\r\n'.bytes())!
- }
- session.conn.write('250 HELP\r\n'.bytes())!
- } else {
- // Simple HELO response
- session.send_response(reply_ok, '${session.helo_domain}')!
- }
-}
-
-// handle_mail processes MAIL FROM command
-fn handle_mail(mut session Session, parts []string) ! {
- if session.helo_domain == '' {
- session.send_response(reply_bad_sequence, 'Please send HELO/EHLO first')!
- return
- }
-
- if parts.len < 2 {
- session.send_response(reply_syntax_error_params, 'Missing FROM parameter')!
- return
- }
-
- from_part := parts[1].to_upper()
- if !from_part.starts_with('FROM:') {
- session.send_response(reply_syntax_error_params, 'Syntax error in FROM parameter')!
- return
- }
-
- // Extract email address from <...>
- addr_start := from_part.index('<') or { -1 }
- addr_end := from_part.last_index('>') or { -1 }
- if addr_start == -1 || addr_end == -1 || addr_start >= addr_end {
- session.send_response(reply_syntax_error_params, 'Invalid email address format')!
- return
- }
-
- session.mail_from = from_part[addr_start + 1..addr_end]
- session.send_response(reply_ok, 'OK')!
-}
-
-// handle_rcpt processes RCPT TO command
-fn handle_rcpt(mut session Session, parts []string) ! {
- if session.mail_from == '' {
- session.send_response(reply_bad_sequence, 'Need MAIL FROM command first')!
- return
- }
-
- if parts.len < 2 {
- session.send_response(reply_syntax_error_params, 'Missing TO parameter')!
- return
- }
-
- to_part := parts[1].to_upper()
- if !to_part.starts_with('TO:') {
- session.send_response(reply_syntax_error_params, 'Syntax error in TO parameter')!
- return
- }
-
- // Extract email address from <...>
- addr_start := to_part.index('<') or { -1 }
- addr_end := to_part.last_index('>') or { -1 }
- if addr_start == -1 || addr_end == -1 || addr_start >= addr_end {
- session.send_response(reply_syntax_error_params, 'Invalid email address format')!
- return
- }
-
- rcpt_addr := to_part[addr_start + 1..addr_end]
-
- // Verify recipient exists in mailbox server
- username := session.server.mailboxserver.account_find_by_email(rcpt_addr) or {
- session.send_response(reply_mailbox_unavailable, 'No such user here')!
- return
- }
-
- session.rcpt_to << rcpt_addr
- session.send_response(reply_ok, 'OK')!
-}
-
-// handle_data processes DATA command
-fn handle_data(mut session Session) ! {
- if session.rcpt_to.len == 0 {
- session.send_response(reply_bad_sequence, 'Need RCPT TO command first')!
- return
- }
-
- session.data_mode = true
- session.send_response(reply_start_mail, 'Start mail input; end with .')!
-}
-
-// handle_data_content processes the email content after DATA command
-fn handle_data_content(mut session Session, line string) ! {
- if line == '.' {
- // End of data
- session.data_mode = false
-
- // Store message for each recipient
- for rcpt in session.rcpt_to {
- username := session.server.mailboxserver.account_find_by_email(rcpt) or {
- eprintln('Failed to find recipient ${rcpt}')
- continue
- }
-
- // Create message in recipient's INBOX
- mut msg := mailbox.Message{
- uid: 0 // Will be assigned by mailbox
- subject: 'New message' // TODO: Parse subject from headers
- body: line // TODO: Accumulate message body
- flags: []string{} // No flags initially
- internal_date: time.now()
- }
- session.server.mailboxserver.message_set(username, 'INBOX', 0, msg) or {
- eprintln('Failed to store message for ${username}: ${err}')
- session.send_response(reply_transaction_failed, 'Failed to store message')!
- return
- }
- }
-
- session.send_response(reply_ok, 'OK')!
- session.reset_session()
- return
- }
-
- // TODO: Accumulate message body
- // For now we just acknowledge the line
-}
-
-// handle_rset processes RSET command
-fn handle_rset(mut session Session) ! {
- session.reset_session()
- session.send_response(reply_ok, 'OK')!
-}
-
-// handle_quit processes QUIT command
-fn handle_quit(mut session Session) ! {
- session.send_response(reply_goodbye, 'Goodbye')!
-}
-
-// handle_auth processes AUTH command
-fn handle_auth(mut session Session, parts []string) ! {
- if parts.len < 2 {
- session.send_response(reply_syntax_error_params, 'Missing authentication type')!
- return
- }
-
- auth_type := parts[1].to_upper()
- if auth_type !in ['PLAIN', 'LOGIN'] {
- session.send_response(reply_syntax_error_params, 'Unsupported authentication type')!
- return
- }
-
- // For demo purposes, accept any credentials
- if auth_type == 'PLAIN' {
- if parts.len < 3 {
- session.send_response(reply_syntax_error_params, 'Missing credentials')!
- return
- }
- // In real implementation, decode base64 credentials and validate
- session.authenticated = true
- session.send_response(reply_ok, 'Authentication successful')!
- } else { // LOGIN
- // Send username prompt
- session.conn.write('334 VXNlcm5hbWU6\r\n'.bytes())! // Base64 encoded "Username:"
- username := session.reader.read_line()!
-
- // Send password prompt
- session.conn.write('334 UGFzc3dvcmQ6\r\n'.bytes())! // Base64 encoded "Password:"
- password := session.reader.read_line()!
-
- // For demo purposes, accept any credentials
- session.authenticated = true
- session.username = username // Store for potential use
- session.send_response(reply_ok, 'Authentication successful')!
- }
-}
diff --git a/lib/servers/mail/smtp/specs.md b/lib/servers/mail/smtp/specs.md
deleted file mode 100644
index e233fc78..00000000
--- a/lib/servers/mail/smtp/specs.md
+++ /dev/null
@@ -1,4893 +0,0 @@
-
-Network Working Group J. Klensin
-Request for Comments: 5321 October 2008
-Obsoletes: 2821
-Updates: 1123
-Category: Standards Track
-
-
- Simple Mail Transfer Protocol
-
-Status of This Memo
-
- This document specifies an Internet standards track protocol for the
- Internet community, and requests discussion and suggestions for
- improvements. Please refer to the current edition of the "Internet
- Official Protocol Standards" (STD 1) for the standardization state
- and status of this protocol. Distribution of this memo is unlimited.
-
-Abstract
-
- This document is a specification of the basic protocol for Internet
- electronic mail transport. It consolidates, updates, and clarifies
- several previous documents, making all or parts of most of them
- obsolete. It covers the SMTP extension mechanisms and best practices
- for the contemporary Internet, but does not provide details about
- particular extensions. Although SMTP was designed as a mail
- transport and delivery protocol, this specification also contains
- information that is important to its use as a "mail submission"
- protocol for "split-UA" (User Agent) mail reading systems and mobile
- environments.
-
-
-
-
-
-
-
-1. Introduction
-
-1.1. Transport of Electronic Mail
-
- The objective of the Simple Mail Transfer Protocol (SMTP) is to
- transfer mail reliably and efficiently.
-
- SMTP is independent of the particular transmission subsystem and
- requires only a reliable ordered data stream channel. While this
- document specifically discusses transport over TCP, other transports
- are possible. Appendices to RFC 821 [1] describe some of them.
-
- An important feature of SMTP is its capability to transport mail
- across multiple networks, usually referred to as "SMTP mail relaying"
- (see Section 3.6). A network consists of the mutually-TCP-accessible
- hosts on the public Internet, the mutually-TCP-accessible hosts on a
- firewall-isolated TCP/IP Intranet, or hosts in some other LAN or WAN
- environment utilizing a non-TCP transport-level protocol. Using
- SMTP, a process can transfer mail to another process on the same
- network or to some other network via a relay or gateway process
- accessible to both networks.
-
- In this way, a mail message may pass through a number of intermediate
- relay or gateway hosts on its path from sender to ultimate recipient.
- The Mail eXchanger mechanisms of the domain name system (RFC 1035
- [2], RFC 974 [12], and Section 5 of this document) are used to
- identify the appropriate next-hop destination for a message being
- transported.
-
-1.2. History and Context for This Document
-
- This document is a specification of the basic protocol for the
- Internet electronic mail transport. It consolidates, updates and
- clarifies, but does not add new or change existing functionality of
- the following:
-
- o the original SMTP (Simple Mail Transfer Protocol) specification of
- RFC 821 [1],
-
- o domain name system requirements and implications for mail
- transport from RFC 1035 [2] and RFC 974 [12],
-
- o the clarifications and applicability statements in RFC 1123 [3],
- and
-
- o material drawn from the SMTP Extension mechanisms in RFC 1869
- [13].
-
-
-
-
-Klensin Standards Track [Page 5]
-
-RFC 5321 SMTP October 2008
-
-
- o Editorial and clarification changes to RFC 2821 [14] to bring that
- specification to Draft Standard.
-
- It obsoletes RFC 821, RFC 974, RFC 1869, and RFC 2821 and updates RFC
- 1123 (replacing the mail transport materials of RFC 1123). However,
- RFC 821 specifies some features that were not in significant use in
- the Internet by the mid-1990s and (in appendices) some additional
- transport models. Those sections are omitted here in the interest of
- clarity and brevity; readers needing them should refer to RFC 821.
-
- It also includes some additional material from RFC 1123 that required
- amplification. This material has been identified in multiple ways,
- mostly by tracking flaming on various lists and newsgroups and
- problems of unusual readings or interpretations that have appeared as
- the SMTP extensions have been deployed. Where this specification
- moves beyond consolidation and actually differs from earlier
- documents, it supersedes them technically as well as textually.
-
- Although SMTP was designed as a mail transport and delivery protocol,
- this specification also contains information that is important to its
- use as a "mail submission" protocol, as recommended for Post Office
- Protocol (POP) (RFC 937 [15], RFC 1939 [16]) and IMAP (RFC 3501
- [17]). In general, the separate mail submission protocol specified
- in RFC 4409 [18] is now preferred to direct use of SMTP; more
- discussion of that subject appears in that document.
-
- Section 2.3 provides definitions of terms specific to this document.
- Except when the historical terminology is necessary for clarity, this
- document uses the current 'client' and 'server' terminology to
- identify the sending and receiving SMTP processes, respectively.
-
- A companion document, RFC 5322 [4], discusses message header sections
- and bodies and specifies formats and structures for them.
-
-1.3. Document Conventions
-
- The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
- "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
- document are to be interpreted as described in RFC 2119 [5]. As each
- of these terms was intentionally and carefully chosen to improve the
- interoperability of email, each use of these terms is to be treated
- as a conformance requirement.
-
- Because this document has a long history and to avoid the risk of
- various errors and of confusing readers and documents that point to
- this one, most examples and the domain names they contain are
- preserved from RFC 2821. Readers are cautioned that these are
-
-
-
-
-Klensin Standards Track [Page 6]
-
-RFC 5321 SMTP October 2008
-
-
- illustrative examples that should not actually be used in either code
- or configuration files.
-
-2. The SMTP Model
-
-2.1. Basic Structure
-
- The SMTP design can be pictured as:
-
- +----------+ +----------+
- +------+ | | | |
- | User |<-->| | SMTP | |
- +------+ | Client- |Commands/Replies| Server- |
- +------+ | SMTP |<-------------->| SMTP | +------+
- | File |<-->| | and Mail | |<-->| File |
- |System| | | | | |System|
- +------+ +----------+ +----------+ +------+
- SMTP client SMTP server
-
- When an SMTP client has a message to transmit, it establishes a two-
- way transmission channel to an SMTP server. The responsibility of an
- SMTP client is to transfer mail messages to one or more SMTP servers,
- or report its failure to do so.
-
- The means by which a mail message is presented to an SMTP client, and
- how that client determines the identifier(s) ("names") of the
- domain(s) to which mail messages are to be transferred, is a local
- matter, and is not addressed by this document. In some cases, the
- designated domain(s), or those determined by an SMTP client, will
- identify the final destination(s) of the mail message. In other
- cases, common with SMTP clients associated with implementations of
- the POP (RFC 937 [15], RFC 1939 [16]) or IMAP (RFC 3501 [17])
- protocols, or when the SMTP client is inside an isolated transport
- service environment, the domain determined will identify an
- intermediate destination through which all mail messages are to be
- relayed. SMTP clients that transfer all traffic regardless of the
- target domains associated with the individual messages, or that do
- not maintain queues for retrying message transmissions that initially
- cannot be completed, may otherwise conform to this specification but
- are not considered fully-capable. Fully-capable SMTP
- implementations, including the relays used by these less capable
- ones, and their destinations, are expected to support all of the
- queuing, retrying, and alternate address functions discussed in this
- specification. In many situations and configurations, the less-
- capable clients discussed above SHOULD be using the message
- submission protocol (RFC 4409 [18]) rather than SMTP.
-
-
-
-
-
-Klensin Standards Track [Page 7]
-
-RFC 5321 SMTP October 2008
-
-
- The means by which an SMTP client, once it has determined a target
- domain, determines the identity of an SMTP server to which a copy of
- a message is to be transferred, and then performs that transfer, is
- covered by this document. To effect a mail transfer to an SMTP
- server, an SMTP client establishes a two-way transmission channel to
- that SMTP server. An SMTP client determines the address of an
- appropriate host running an SMTP server by resolving a destination
- domain name to either an intermediate Mail eXchanger host or a final
- target host.
-
- An SMTP server may be either the ultimate destination or an
- intermediate "relay" (that is, it may assume the role of an SMTP
- client after receiving the message) or "gateway" (that is, it may
- transport the message further using some protocol other than SMTP).
- SMTP commands are generated by the SMTP client and sent to the SMTP
- server. SMTP replies are sent from the SMTP server to the SMTP
- client in response to the commands.
-
- In other words, message transfer can occur in a single connection
- between the original SMTP-sender and the final SMTP-recipient, or can
- occur in a series of hops through intermediary systems. In either
- case, once the server has issued a success response at the end of the
- mail data, a formal handoff of responsibility for the message occurs:
- the protocol requires that a server MUST accept responsibility for
- either delivering the message or properly reporting the failure to do
- so (see Sections 6.1, 6.2, and 7.8, below).
-
- Once the transmission channel is established and initial handshaking
- is completed, the SMTP client normally initiates a mail transaction.
- Such a transaction consists of a series of commands to specify the
- originator and destination of the mail and transmission of the
- message content (including any lines in the header section or other
- structure) itself. When the same message is sent to multiple
- recipients, this protocol encourages the transmission of only one
- copy of the data for all recipients at the same destination (or
- intermediate relay) host.
-
- The server responds to each command with a reply; replies may
- indicate that the command was accepted, that additional commands are
- expected, or that a temporary or permanent error condition exists.
- Commands specifying the sender or recipients may include server-
- permitted SMTP service extension requests, as discussed in
- Section 2.2. The dialog is purposely lock-step, one-at-a-time,
- although this can be modified by mutually agreed upon extension
- requests such as command pipelining (RFC 2920 [19]).
-
- Once a given mail message has been transmitted, the client may either
- request that the connection be shut down or may initiate other mail
-
-
-
-Klensin Standards Track [Page 8]
-
-RFC 5321 SMTP October 2008
-
-
- transactions. In addition, an SMTP client may use a connection to an
- SMTP server for ancillary services such as verification of email
- addresses or retrieval of mailing list subscriber addresses.
-
- As suggested above, this protocol provides mechanisms for the
- transmission of mail. Historically, this transmission normally
- occurred directly from the sending user's host to the receiving
- user's host when the two hosts are connected to the same transport
- service. When they are not connected to the same transport service,
- transmission occurs via one or more relay SMTP servers. A very
- common case in the Internet today involves submission of the original
- message to an intermediate, "message submission" server, which is
- similar to a relay but has some additional properties; such servers
- are discussed in Section 2.3.10 and at some length in RFC 4409 [18].
- An intermediate host that acts as either an SMTP relay or as a
- gateway into some other transmission environment is usually selected
- through the use of the domain name service (DNS) Mail eXchanger
- mechanism.
-
- Usually, intermediate hosts are determined via the DNS MX record, not
- by explicit "source" routing (see Section 5 and Appendix C and
- Appendix F.2).
-
-2.2. The Extension Model
-
-2.2.1. Background
-
- In an effort that started in 1990, approximately a decade after RFC
- 821 was completed, the protocol was modified with a "service
- extensions" model that permits the client and server to agree to
- utilize shared functionality beyond the original SMTP requirements.
- The SMTP extension mechanism defines a means whereby an extended SMTP
- client and server may recognize each other, and the server can inform
- the client as to the service extensions that it supports.
-
- Contemporary SMTP implementations MUST support the basic extension
- mechanisms. For instance, servers MUST support the EHLO command even
- if they do not implement any specific extensions and clients SHOULD
- preferentially utilize EHLO rather than HELO. (However, for
- compatibility with older conforming implementations, SMTP clients and
- servers MUST support the original HELO mechanisms as a fallback.)
- Unless the different characteristics of HELO must be identified for
- interoperability purposes, this document discusses only EHLO.
-
- SMTP is widely deployed and high-quality implementations have proven
- to be very robust. However, the Internet community now considers
- some services to be important that were not anticipated when the
- protocol was first designed. If support for those services is to be
-
-
-
-Klensin Standards Track [Page 9]
-
-RFC 5321 SMTP October 2008
-
-
- added, it must be done in a way that permits older implementations to
- continue working acceptably. The extension framework consists of:
-
- o The SMTP command EHLO, superseding the earlier HELO,
-
- o a registry of SMTP service extensions,
-
- o additional parameters to the SMTP MAIL and RCPT commands, and
-
- o optional replacements for commands defined in this protocol, such
- as for DATA in non-ASCII transmissions (RFC 3030 [20]).
-
- SMTP's strength comes primarily from its simplicity. Experience with
- many protocols has shown that protocols with few options tend towards
- ubiquity, whereas protocols with many options tend towards obscurity.
-
- Each and every extension, regardless of its benefits, must be
- carefully scrutinized with respect to its implementation, deployment,
- and interoperability costs. In many cases, the cost of extending the
- SMTP service will likely outweigh the benefit.
-
-2.2.2. Definition and Registration of Extensions
-
- The IANA maintains a registry of SMTP service extensions. A
- corresponding EHLO keyword value is associated with each extension.
- Each service extension registered with the IANA must be defined in a
- formal Standards-Track or IESG-approved Experimental protocol
- document. The definition must include:
-
- o the textual name of the SMTP service extension;
-
- o the EHLO keyword value associated with the extension;
-
- o the syntax and possible values of parameters associated with the
- EHLO keyword value;
-
- o any additional SMTP verbs associated with the extension
- (additional verbs will usually be, but are not required to be, the
- same as the EHLO keyword value);
-
- o any new parameters the extension associates with the MAIL or RCPT
- verbs;
-
- o a description of how support for the extension affects the
- behavior of a server and client SMTP; and
-
-
-
-
-
-
-Klensin Standards Track [Page 10]
-
-RFC 5321 SMTP October 2008
-
-
- o the increment by which the extension is increasing the maximum
- length of the commands MAIL and/or RCPT, over that specified in
- this Standard.
-
- In addition, any EHLO keyword value starting with an upper or lower
- case "X" refers to a local SMTP service extension used exclusively
- through bilateral agreement. Keywords beginning with "X" MUST NOT be
- used in a registered service extension. Conversely, keyword values
- presented in the EHLO response that do not begin with "X" MUST
- correspond to a Standard, Standards-Track, or IESG-approved
- Experimental SMTP service extension registered with IANA. A
- conforming server MUST NOT offer non-"X"-prefixed keyword values that
- are not described in a registered extension.
-
- Additional verbs and parameter names are bound by the same rules as
- EHLO keywords; specifically, verbs beginning with "X" are local
- extensions that may not be registered or standardized. Conversely,
- verbs not beginning with "X" must always be registered.
-
-2.2.3. Special Issues with Extensions
-
- Extensions that change fairly basic properties of SMTP operation are
- permitted. The text in other sections of this document must be
- understood in that context. In particular, extensions can change the
- minimum limits specified in Section 4.5.3, can change the ASCII
- character set requirement as mentioned above, or can introduce some
- optional modes of message handling.
-
- In particular, if an extension implies that the delivery path
- normally supports special features of that extension, and an
- intermediate SMTP system finds a next hop that does not support the
- required extension, it MAY choose, based on the specific extension
- and circumstances, to requeue the message and try later and/or try an
- alternate MX host. If this strategy is employed, the timeout to fall
- back to an unextended format (if one is available) SHOULD be less
- than the normal timeout for bouncing as undeliverable (e.g., if
- normal timeout is three days, the requeue timeout before attempting
- to transmit the mail without the extension might be one day).
-
-2.3. SMTP Terminology
-
-2.3.1. Mail Objects
-
- SMTP transports a mail object. A mail object contains an envelope
- and content.
-
- The SMTP envelope is sent as a series of SMTP protocol units
- (described in Section 3). It consists of an originator address (to
-
-
-
-Klensin Standards Track [Page 11]
-
-RFC 5321 SMTP October 2008
-
-
- which error reports should be directed), one or more recipient
- addresses, and optional protocol extension material. Historically,
- variations on the reverse-path (originator) address specification
- command (MAIL) could be used to specify alternate delivery modes,
- such as immediate display; those variations have now been deprecated
- (see Appendix F and Appendix F.6).
-
- The SMTP content is sent in the SMTP DATA protocol unit and has two
- parts: the header section and the body. If the content conforms to
- other contemporary standards, the header section consists of a
- collection of header fields, each consisting of a header name, a
- colon, and data, structured as in the message format specification
- (RFC 5322 [4]); the body, if structured, is defined according to MIME
- (RFC 2045 [21]). The content is textual in nature, expressed using
- the US-ASCII repertoire [6]. Although SMTP extensions (such as
- "8BITMIME", RFC 1652 [22]) may relax this restriction for the content
- body, the content header fields are always encoded using the US-ASCII
- repertoire. Two MIME extensions (RFC 2047 [23] and RFC 2231 [24])
- define an algorithm for representing header values outside the US-
- ASCII repertoire, while still encoding them using the US-ASCII
- repertoire.
-
-2.3.2. Senders and Receivers
-
- In RFC 821, the two hosts participating in an SMTP transaction were
- described as the "SMTP-sender" and "SMTP-receiver". This document
- has been changed to reflect current industry terminology and hence
- refers to them as the "SMTP client" (or sometimes just "the client")
- and "SMTP server" (or just "the server"), respectively. Since a
- given host may act both as server and client in a relay situation,
- "receiver" and "sender" terminology is still used where needed for
- clarity.
-
-2.3.3. Mail Agents and Message Stores
-
- Additional mail system terminology became common after RFC 821 was
- published and, where convenient, is used in this specification. In
- particular, SMTP servers and clients provide a mail transport service
- and therefore act as "Mail Transfer Agents" (MTAs). "Mail User
- Agents" (MUAs or UAs) are normally thought of as the sources and
- targets of mail. At the source, an MUA might collect mail to be
- transmitted from a user and hand it off to an MTA; the final
- ("delivery") MTA would be thought of as handing the mail off to an
- MUA (or at least transferring responsibility to it, e.g., by
- depositing the message in a "message store"). However, while these
- terms are used with at least the appearance of great precision in
- other environments, the implied boundaries between MUAs and MTAs
- often do not accurately match common, and conforming, practices with
-
-
-
-Klensin Standards Track [Page 12]
-
-RFC 5321 SMTP October 2008
-
-
- Internet mail. Hence, the reader should be cautious about inferring
- the strong relationships and responsibilities that might be implied
- if these terms were used elsewhere.
-
-2.3.4. Host
-
- For the purposes of this specification, a host is a computer system
- attached to the Internet (or, in some cases, to a private TCP/IP
- network) and supporting the SMTP protocol. Hosts are known by names
- (see the next section); they SHOULD NOT be identified by numerical
- addresses, i.e., by address literals as described in Section 4.1.2.
-
-2.3.5. Domain Names
-
- A domain name (or often just a "domain") consists of one or more
- components, separated by dots if more than one appears. In the case
- of a top-level domain used by itself in an email address, a single
- string is used without any dots. This makes the requirement,
- described in more detail below, that only fully-qualified domain
- names appear in SMTP transactions on the public Internet,
- particularly important where top-level domains are involved. These
- components ("labels" in DNS terminology, RFC 1035 [2]) are restricted
- for SMTP purposes to consist of a sequence of letters, digits, and
- hyphens drawn from the ASCII character set [6]. Domain names are
- used as names of hosts and of other entities in the domain name
- hierarchy. For example, a domain may refer to an alias (label of a
- CNAME RR) or the label of Mail eXchanger records to be used to
- deliver mail instead of representing a host name. See RFC 1035 [2]
- and Section 5 of this specification.
-
- The domain name, as described in this document and in RFC 1035 [2],
- is the entire, fully-qualified name (often referred to as an "FQDN").
- A domain name that is not in FQDN form is no more than a local alias.
- Local aliases MUST NOT appear in any SMTP transaction.
-
- Only resolvable, fully-qualified domain names (FQDNs) are permitted
- when domain names are used in SMTP. In other words, names that can
- be resolved to MX RRs or address (i.e., A or AAAA) RRs (as discussed
- in Section 5) are permitted, as are CNAME RRs whose targets can be
- resolved, in turn, to MX or address RRs. Local nicknames or
- unqualified names MUST NOT be used. There are two exceptions to the
- rule requiring FQDNs:
-
- o The domain name given in the EHLO command MUST be either a primary
- host name (a domain name that resolves to an address RR) or, if
- the host has no name, an address literal, as described in
- Section 4.1.3 and discussed further in the EHLO discussion of
- Section 4.1.4.
-
-
-
-Klensin Standards Track [Page 13]
-
-RFC 5321 SMTP October 2008
-
-
- o The reserved mailbox name "postmaster" may be used in a RCPT
- command without domain qualification (see Section 4.1.1.3) and
- MUST be accepted if so used.
-
-2.3.6. Buffer and State Table
-
- SMTP sessions are stateful, with both parties carefully maintaining a
- common view of the current state. In this document, we model this
- state by a virtual "buffer" and a "state table" on the server that
- may be used by the client to, for example, "clear the buffer" or
- "reset the state table", causing the information in the buffer to be
- discarded and the state to be returned to some previous state.
-
-2.3.7. Commands and Replies
-
- SMTP commands and, unless altered by a service extension, message
- data, are transmitted from the sender to the receiver via the
- transmission channel in "lines".
-
- An SMTP reply is an acknowledgment (positive or negative) sent in
- "lines" from receiver to sender via the transmission channel in
- response to a command. The general form of a reply is a numeric
- completion code (indicating failure or success) usually followed by a
- text string. The codes are for use by programs and the text is
- usually intended for human users. RFC 3463 [25], specifies further
- structuring of the reply strings, including the use of supplemental
- and more specific completion codes (see also RFC 5248 [26]).
-
-2.3.8. Lines
-
- Lines consist of zero or more data characters terminated by the
- sequence ASCII character "CR" (hex value 0D) followed immediately by
- ASCII character "LF" (hex value 0A). This termination sequence is
- denoted as in this document. Conforming implementations MUST
- NOT recognize or generate any other character or character sequence
- as a line terminator. Limits MAY be imposed on line lengths by
- servers (see Section 4).
-
- In addition, the appearance of "bare" "CR" or "LF" characters in text
- (i.e., either without the other) has a long history of causing
- problems in mail implementations and applications that use the mail
- system as a tool. SMTP client implementations MUST NOT transmit
- these characters except when they are intended as line terminators
- and then MUST, as indicated above, transmit them only as a
- sequence.
-
-
-
-
-
-
-Klensin Standards Track [Page 14]
-
-RFC 5321 SMTP October 2008
-
-
-2.3.9. Message Content and Mail Data
-
- The terms "message content" and "mail data" are used interchangeably
- in this document to describe the material transmitted after the DATA
- command is accepted and before the end of data indication is
- transmitted. Message content includes the message header section and
- the possibly structured message body. The MIME specification (RFC
- 2045 [21]) provides the standard mechanisms for structured message
- bodies.
-
-2.3.10. Originator, Delivery, Relay, and Gateway Systems
-
- This specification makes a distinction among four types of SMTP
- systems, based on the role those systems play in transmitting
- electronic mail. An "originating" system (sometimes called an SMTP
- originator) introduces mail into the Internet or, more generally,
- into a transport service environment. A "delivery" SMTP system is
- one that receives mail from a transport service environment and
- passes it to a mail user agent or deposits it in a message store that
- a mail user agent is expected to subsequently access. A "relay" SMTP
- system (usually referred to just as a "relay") receives mail from an
- SMTP client and transmits it, without modification to the message
- data other than adding trace information, to another SMTP server for
- further relaying or for delivery.
-
- A "gateway" SMTP system (usually referred to just as a "gateway")
- receives mail from a client system in one transport environment and
- transmits it to a server system in another transport environment.
- Differences in protocols or message semantics between the transport
- environments on either side of a gateway may require that the gateway
- system perform transformations to the message that are not permitted
- to SMTP relay systems. For the purposes of this specification,
- firewalls that rewrite addresses should be considered as gateways,
- even if SMTP is used on both sides of them (see RFC 2979 [27]).
-
-2.3.11. Mailbox and Address
-
- As used in this specification, an "address" is a character string
- that identifies a user to whom mail will be sent or a location into
- which mail will be deposited. The term "mailbox" refers to that
- depository. The two terms are typically used interchangeably unless
- the distinction between the location in which mail is placed (the
- mailbox) and a reference to it (the address) is important. An
- address normally consists of user and domain specifications. The
- standard mailbox naming convention is defined to be
- "local-part@domain"; contemporary usage permits a much broader set of
- applications than simple "user names". Consequently, and due to a
- long history of problems when intermediate hosts have attempted to
-
-
-
-Klensin Standards Track [Page 15]
-
-RFC 5321 SMTP October 2008
-
-
- optimize transport by modifying them, the local-part MUST be
- interpreted and assigned semantics only by the host specified in the
- domain part of the address.
-
-2.4. General Syntax Principles and Transaction Model
-
- SMTP commands and replies have a rigid syntax. All commands begin
- with a command verb. All replies begin with a three digit numeric
- code. In some commands and replies, arguments are required following
- the verb or reply code. Some commands do not accept arguments (after
- the verb), and some reply codes are followed, sometimes optionally,
- by free form text. In both cases, where text appears, it is
- separated from the verb or reply code by a space character. Complete
- definitions of commands and replies appear in Section 4.
-
- Verbs and argument values (e.g., "TO:" or "to:" in the RCPT command
- and extension name keywords) are not case sensitive, with the sole
- exception in this specification of a mailbox local-part (SMTP
- Extensions may explicitly specify case-sensitive elements). That is,
- a command verb, an argument value other than a mailbox local-part,
- and free form text MAY be encoded in upper case, lower case, or any
- mixture of upper and lower case with no impact on its meaning. The
- local-part of a mailbox MUST BE treated as case sensitive.
- Therefore, SMTP implementations MUST take care to preserve the case
- of mailbox local-parts. In particular, for some hosts, the user
- "smith" is different from the user "Smith". However, exploiting the
- case sensitivity of mailbox local-parts impedes interoperability and
- is discouraged. Mailbox domains follow normal DNS rules and are
- hence not case sensitive.
-
- A few SMTP servers, in violation of this specification (and RFC 821)
- require that command verbs be encoded by clients in upper case.
- Implementations MAY wish to employ this encoding to accommodate those
- servers.
-
- The argument clause consists of a variable-length character string
- ending with the end of the line, i.e., with the character sequence
- . The receiver will take no action until this sequence is
- received.
-
- The syntax for each command is shown with the discussion of that
- command. Common elements and parameters are shown in Section 4.1.2.
-
- Commands and replies are composed of characters from the ASCII
- character set [6]. When the transport service provides an 8-bit byte
- (octet) transmission channel, each 7-bit character is transmitted,
- right justified, in an octet with the high-order bit cleared to zero.
- More specifically, the unextended SMTP service provides 7-bit
-
-
-
-Klensin Standards Track [Page 16]
-
-RFC 5321 SMTP October 2008
-
-
- transport only. An originating SMTP client that has not successfully
- negotiated an appropriate extension with a particular server (see the
- next paragraph) MUST NOT transmit messages with information in the
- high-order bit of octets. If such messages are transmitted in
- violation of this rule, receiving SMTP servers MAY clear the high-
- order bit or reject the message as invalid. In general, a relay SMTP
- SHOULD assume that the message content it has received is valid and,
- assuming that the envelope permits doing so, relay it without
- inspecting that content. Of course, if the content is mislabeled and
- the data path cannot accept the actual content, this may result in
- the ultimate delivery of a severely garbled message to the recipient.
- Delivery SMTP systems MAY reject such messages, or return them as
- undeliverable, rather than deliver them. In the absence of a server-
- offered extension explicitly permitting it, a sending SMTP system is
- not permitted to send envelope commands in any character set other
- than US-ASCII. Receiving systems SHOULD reject such commands,
- normally using "500 syntax error - invalid character" replies.
-
- 8-bit message content transmission MAY be requested of the server by
- a client using extended SMTP facilities, notably the "8BITMIME"
- extension, RFC 1652 [22]. 8BITMIME SHOULD be supported by SMTP
- servers. However, it MUST NOT be construed as authorization to
- transmit unrestricted 8-bit material, nor does 8BITMIME authorize
- transmission of any envelope material in other than ASCII. 8BITMIME
- MUST NOT be requested by senders for material with the high bit on
- that is not in MIME format with an appropriate content-transfer
- encoding; servers MAY reject such messages.
-
- The metalinguistic notation used in this document corresponds to the
- "Augmented BNF" used in other Internet mail system documents. The
- reader who is not familiar with that syntax should consult the ABNF
- specification in RFC 5234 [7]. Metalanguage terms used in running
- text are surrounded by pointed brackets (e.g., ) for clarity.
- The reader is cautioned that the grammar expressed in the
- metalanguage is not comprehensive. There are many instances in which
- provisions in the text constrain or otherwise modify the syntax or
- semantics implied by the grammar.
-
-3. The SMTP Procedures: An Overview
-
- This section contains descriptions of the procedures used in SMTP:
- session initiation, mail transaction, forwarding mail, verifying
- mailbox names and expanding mailing lists, and opening and closing
- exchanges. Comments on relaying, a note on mail domains, and a
- discussion of changing roles are included at the end of this section.
- Several complete scenarios are presented in Appendix D.
-
-
-
-
-
-Klensin Standards Track [Page 17]
-
-RFC 5321 SMTP October 2008
-
-
-3.1. Session Initiation
-
- An SMTP session is initiated when a client opens a connection to a
- server and the server responds with an opening message.
-
- SMTP server implementations MAY include identification of their
- software and version information in the connection greeting reply
- after the 220 code, a practice that permits more efficient isolation
- and repair of any problems. Implementations MAY make provision for
- SMTP servers to disable the software and version announcement where
- it causes security concerns. While some systems also identify their
- contact point for mail problems, this is not a substitute for
- maintaining the required "postmaster" address (see Section 4).
-
- The SMTP protocol allows a server to formally reject a mail session
- while still allowing the initial connection as follows: a 554
- response MAY be given in the initial connection opening message
- instead of the 220. A server taking this approach MUST still wait
- for the client to send a QUIT (see Section 4.1.1.10) before closing
- the connection and SHOULD respond to any intervening commands with
- "503 bad sequence of commands". Since an attempt to make an SMTP
- connection to such a system is probably in error, a server returning
- a 554 response on connection opening SHOULD provide enough
- information in the reply text to facilitate debugging of the sending
- system.
-
-3.2. Client Initiation
-
- Once the server has sent the greeting (welcoming) message and the
- client has received it, the client normally sends the EHLO command to
- the server, indicating the client's identity. In addition to opening
- the session, use of EHLO indicates that the client is able to process
- service extensions and requests that the server provide a list of the
- extensions it supports. Older SMTP systems that are unable to
- support service extensions, and contemporary clients that do not
- require service extensions in the mail session being initiated, MAY
- use HELO instead of EHLO. Servers MUST NOT return the extended EHLO-
- style response to a HELO command. For a particular connection
- attempt, if the server returns a "command not recognized" response to
- EHLO, the client SHOULD be able to fall back and send HELO.
-
- In the EHLO command, the host sending the command identifies itself;
- the command may be interpreted as saying "Hello, I am " (and,
- in the case of EHLO, "and I support service extension requests").
-
-
-
-
-
-
-
-Klensin Standards Track [Page 18]
-
-RFC 5321 SMTP October 2008
-
-
-3.3. Mail Transactions
-
- There are three steps to SMTP mail transactions. The transaction
- starts with a MAIL command that gives the sender identification. (In
- general, the MAIL command may be sent only when no mail transaction
- is in progress; see Section 4.1.4.) A series of one or more RCPT
- commands follows, giving the receiver information. Then, a DATA
- command initiates transfer of the mail data and is terminated by the
- "end of mail" data indicator, which also confirms the transaction.
-
- The first step in the procedure is the MAIL command.
-
- MAIL FROM: [SP ]
-
- This command tells the SMTP-receiver that a new mail transaction is
- starting and to reset all its state tables and buffers, including any
- recipients or mail data. The portion of the first or
- only argument contains the source mailbox (between "<" and ">"
- brackets), which can be used to report errors (see Section 4.2 for a
- discussion of error reporting). If accepted, the SMTP server returns
- a "250 OK" reply. If the mailbox specification is not acceptable for
- some reason, the server MUST return a reply indicating whether the
- failure is permanent (i.e., will occur again if the client tries to
- send the same address again) or temporary (i.e., the address might be
- accepted if the client tries again later). Despite the apparent
- scope of this requirement, there are circumstances in which the
- acceptability of the reverse-path may not be determined until one or
- more forward-paths (in RCPT commands) can be examined. In those
- cases, the server MAY reasonably accept the reverse-path (with a 250
- reply) and then report problems after the forward-paths are received
- and examined. Normally, failures produce 550 or 553 replies.
-
- Historically, the was permitted to contain more than
- just a mailbox; however, contemporary systems SHOULD NOT use source
- routing (see Appendix C).
-
- The optional are associated with negotiated SMTP
- service extensions (see Section 2.2).
-
- The second step in the procedure is the RCPT command. This step of
- the procedure can be repeated any number of times.
-
- RCPT TO: [ SP ]
-
- The first or only argument to this command includes a forward-path
- (normally a mailbox and domain, always surrounded by "<" and ">"
- brackets) identifying one recipient. If accepted, the SMTP server
- returns a "250 OK" reply and stores the forward-path. If the
-
-
-
-Klensin Standards Track [Page 19]
-
-RFC 5321 SMTP October 2008
-
-
- recipient is known not to be a deliverable address, the SMTP server
- returns a 550 reply, typically with a string such as "no such user -
- " and the mailbox name (other circumstances and reply codes are
- possible).
-
- The can contain more than just a mailbox.
- Historically, the was permitted to contain a source
- routing list of hosts and the destination mailbox; however,
- contemporary SMTP clients SHOULD NOT utilize source routes (see
- Appendix C). Servers MUST be prepared to encounter a list of source
- routes in the forward-path, but they SHOULD ignore the routes or MAY
- decline to support the relaying they imply. Similarly, servers MAY
- decline to accept mail that is destined for other hosts or systems.
- These restrictions make a server useless as a relay for clients that
- do not support full SMTP functionality. Consequently, restricted-
- capability clients MUST NOT assume that any SMTP server on the
- Internet can be used as their mail processing (relaying) site. If a
- RCPT command appears without a previous MAIL command, the server MUST
- return a 503 "Bad sequence of commands" response. The optional
- are associated with negotiated SMTP service
- extensions (see Section 2.2).
-
- Since it has been a common source of errors, it is worth noting that
- spaces are not permitted on either side of the colon following FROM
- in the MAIL command or TO in the RCPT command. The syntax is exactly
- as given above.
-
- The third step in the procedure is the DATA command (or some
- alternative specified in a service extension).
-
- DATA
-
- If accepted, the SMTP server returns a 354 Intermediate reply and
- considers all succeeding lines up to but not including the end of
- mail data indicator to be the message text. When the end of text is
- successfully received and stored, the SMTP-receiver sends a "250 OK"
- reply.
-
- Since the mail data is sent on the transmission channel, the end of
- mail data must be indicated so that the command and reply dialog can
- be resumed. SMTP indicates the end of the mail data by sending a
- line containing only a "." (period or full stop). A transparency
- procedure is used to prevent this from interfering with the user's
- text (see Section 4.5.2).
-
- The end of mail data indicator also confirms the mail transaction and
- tells the SMTP server to now process the stored recipients and mail
-
-
-
-
-Klensin Standards Track [Page 20]
-
-RFC 5321 SMTP October 2008
-
-
- data. If accepted, the SMTP server returns a "250 OK" reply. The
- DATA command can fail at only two points in the protocol exchange:
-
- If there was no MAIL, or no RCPT, command, or all such commands were
- rejected, the server MAY return a "command out of sequence" (503) or
- "no valid recipients" (554) reply in response to the DATA command.
- If one of those replies (or any other 5yz reply) is received, the
- client MUST NOT send the message data; more generally, message data
- MUST NOT be sent unless a 354 reply is received.
-
- If the verb is initially accepted and the 354 reply issued, the DATA
- command should fail only if the mail transaction was incomplete (for
- example, no recipients), if resources were unavailable (including, of
- course, the server unexpectedly becoming unavailable), or if the
- server determines that the message should be rejected for policy or
- other reasons.
-
- However, in practice, some servers do not perform recipient
- verification until after the message text is received. These servers
- SHOULD treat a failure for one or more recipients as a "subsequent
- failure" and return a mail message as discussed in Section 6 and, in
- particular, in Section 6.1. Using a "550 mailbox not found" (or
- equivalent) reply code after the data are accepted makes it difficult
- or impossible for the client to determine which recipients failed.
-
- When the RFC 822 format ([28], [4]) is being used, the mail data
- include the header fields such as those named Date, Subject, To, Cc,
- and From. Server SMTP systems SHOULD NOT reject messages based on
- perceived defects in the RFC 822 or MIME (RFC 2045 [21]) message
- header section or message body. In particular, they MUST NOT reject
- messages in which the numbers of Resent-header fields do not match or
- Resent-to appears without Resent-from and/or Resent-date.
-
- Mail transaction commands MUST be used in the order discussed above.
-
-3.4. Forwarding for Address Correction or Updating
-
- Forwarding support is most often required to consolidate and simplify
- addresses within, or relative to, some enterprise and less frequently
- to establish addresses to link a person's prior address with a
- current one. Silent forwarding of messages (without server
- notification to the sender), for security or non-disclosure purposes,
- is common in the contemporary Internet.
-
- In both the enterprise and the "new address" cases, information
- hiding (and sometimes security) considerations argue against exposure
- of the "final" address through the SMTP protocol as a side effect of
- the forwarding activity. This may be especially important when the
-
-
-
-Klensin Standards Track [Page 21]
-
-RFC 5321 SMTP October 2008
-
-
- final address may not even be reachable by the sender. Consequently,
- the "forwarding" mechanisms described in Section 3.2 of RFC 821, and
- especially the 251 (corrected destination) and 551 reply codes from
- RCPT must be evaluated carefully by implementers and, when they are
- available, by those configuring systems (see also Section 7.4).
-
- In particular:
-
- o Servers MAY forward messages when they are aware of an address
- change. When they do so, they MAY either provide address-updating
- information with a 251 code, or may forward "silently" and return
- a 250 code. However, if a 251 code is used, they MUST NOT assume
- that the client will actually update address information or even
- return that information to the user.
-
- Alternately,
-
- o Servers MAY reject messages or return them as non-deliverable when
- they cannot be delivered precisely as addressed. When they do so,
- they MAY either provide address-updating information with a 551
- code, or may reject the message as undeliverable with a 550 code
- and no address-specific information. However, if a 551 code is
- used, they MUST NOT assume that the client will actually update
- address information or even return that information to the user.
-
- SMTP server implementations that support the 251 and/or 551 reply
- codes SHOULD provide configuration mechanisms so that sites that
- conclude that they would undesirably disclose information can disable
- or restrict their use.
-
-3.5. Commands for Debugging Addresses
-
-3.5.1. Overview
-
- SMTP provides commands to verify a user name or obtain the content of
- a mailing list. This is done with the VRFY and EXPN commands, which
- have character string arguments. Implementations SHOULD support VRFY
- and EXPN (however, see Section 3.5.2 and Section 7.3).
-
- For the VRFY command, the string is a user name or a user name and
- domain (see below). If a normal (i.e., 250) response is returned,
- the response MAY include the full name of the user and MUST include
- the mailbox of the user. It MUST be in either of the following
- forms:
-
- User Name
- local-part@domain
-
-
-
-
-Klensin Standards Track [Page 22]
-
-RFC 5321 SMTP October 2008
-
-
- When a name that is the argument to VRFY could identify more than one
- mailbox, the server MAY either note the ambiguity or identify the
- alternatives. In other words, any of the following are legitimate
- responses to VRFY:
-
- 553 User ambiguous
-
- or
-
- 553- Ambiguous; Possibilities are
- 553-Joe Smith
- 553-Harry Smith
- 553 Melvin Smith
-
- or
-
- 553-Ambiguous; Possibilities
- 553-
- 553-
- 553
-
- Under normal circumstances, a client receiving a 553 reply would be
- expected to expose the result to the user. Use of exactly the forms
- given, and the "user ambiguous" or "ambiguous" keywords, possibly
- supplemented by extended reply codes, such as those described in RFC
- 3463 [25], will facilitate automated translation into other languages
- as needed. Of course, a client that was highly automated or that was
- operating in another language than English might choose to try to
- translate the response to return some other indication to the user
- than the literal text of the reply, or to take some automated action
- such as consulting a directory service for additional information
- before reporting to the user.
-
- For the EXPN command, the string identifies a mailing list, and the
- successful (i.e., 250) multiline response MAY include the full name
- of the users and MUST give the mailboxes on the mailing list.
-
- In some hosts, the distinction between a mailing list and an alias
- for a single mailbox is a bit fuzzy, since a common data structure
- may hold both types of entries, and it is possible to have mailing
- lists containing only one mailbox. If a request is made to apply
- VRFY to a mailing list, a positive response MAY be given if a message
- so addressed would be delivered to everyone on the list, otherwise an
- error SHOULD be reported (e.g., "550 That is a mailing list, not a
- user" or "252 Unable to verify members of mailing list"). If a
- request is made to expand a user name, the server MAY return a
-
-
-
-
-
-Klensin Standards Track [Page 23]
-
-RFC 5321 SMTP October 2008
-
-
- positive response consisting of a list containing one name, or an
- error MAY be reported (e.g., "550 That is a user name, not a mailing
- list").
-
- In the case of a successful multiline reply (normal for EXPN),
- exactly one mailbox is to be specified on each line of the reply.
- The case of an ambiguous request is discussed above.
-
- "User name" is a fuzzy term and has been used deliberately. An
- implementation of the VRFY or EXPN commands MUST include at least
- recognition of local mailboxes as "user names". However, since
- current Internet practice often results in a single host handling
- mail for multiple domains, hosts, especially hosts that provide this
- functionality, SHOULD accept the "local-part@domain" form as a "user
- name"; hosts MAY also choose to recognize other strings as "user
- names".
-
- The case of expanding a mailbox list requires a multiline reply, such
- as:
-
- C: EXPN Example-People
- S: 250-Jon Postel
- S: 250-Fred Fonebone
- S: 250 Sam Q. Smith
-
- or
-
- C: EXPN Executive-Washroom-List
- S: 550 Access Denied to You.
-
- The character string arguments of the VRFY and EXPN commands cannot
- be further restricted due to the variety of implementations of the
- user name and mailbox list concepts. On some systems, it may be
- appropriate for the argument of the EXPN command to be a file name
- for a file containing a mailing list, but again there are a variety
- of file naming conventions in the Internet. Similarly, historical
- variations in what is returned by these commands are such that the
- response SHOULD be interpreted very carefully, if at all, and SHOULD
- generally only be used for diagnostic purposes.
-
-3.5.2. VRFY Normal Response
-
- When normal (2yz or 551) responses are returned from a VRFY or EXPN
- request, the reply MUST include the name using a
- "" construction, where "domain" is a fully-
- qualified domain name. In circumstances exceptional enough to
- justify violating the intent of this specification, free-form text
- MAY be returned. In order to facilitate parsing by both computers
-
-
-
-Klensin Standards Track [Page 24]
-
-RFC 5321 SMTP October 2008
-
-
- and people, addresses SHOULD appear in pointed brackets. When
- addresses, rather than free-form debugging information, are returned,
- EXPN and VRFY MUST return only valid domain addresses that are usable
- in SMTP RCPT commands. Consequently, if an address implies delivery
- to a program or other system, the mailbox name used to reach that
- target MUST be given. Paths (explicit source routes) MUST NOT be
- returned by VRFY or EXPN.
-
- Server implementations SHOULD support both VRFY and EXPN. For
- security reasons, implementations MAY provide local installations a
- way to disable either or both of these commands through configuration
- options or the equivalent (see Section 7.3). When these commands are
- supported, they are not required to work across relays when relaying
- is supported. Since they were both optional in RFC 821, but VRFY was
- made mandatory in RFC 1123 [3], if EXPN is supported, it MUST be
- listed as a service extension in an EHLO response. VRFY MAY be
- listed as a convenience but, since support for it is required, SMTP
- clients are not required to check for its presence on the extension
- list before using it.
-
-3.5.3. Meaning of VRFY or EXPN Success Response
-
- A server MUST NOT return a 250 code in response to a VRFY or EXPN
- command unless it has actually verified the address. In particular,
- a server MUST NOT return 250 if all it has done is to verify that the
- syntax given is valid. In that case, 502 (Command not implemented)
- or 500 (Syntax error, command unrecognized) SHOULD be returned. As
- stated elsewhere, implementation (in the sense of actually validating
- addresses and returning information) of VRFY and EXPN are strongly
- recommended. Hence, implementations that return 500 or 502 for VRFY
- are not in full compliance with this specification.
-
- There may be circumstances where an address appears to be valid but
- cannot reasonably be verified in real time, particularly when a
- server is acting as a mail exchanger for another server or domain.
- "Apparent validity", in this case, would normally involve at least
- syntax checking and might involve verification that any domains
- specified were ones to which the host expected to be able to relay
- mail. In these situations, reply code 252 SHOULD be returned. These
- cases parallel the discussion of RCPT verification in Section 2.1.
- Similarly, the discussion in Section 3.4 applies to the use of reply
- codes 251 and 551 with VRFY (and EXPN) to indicate addresses that are
- recognized but that would be forwarded or rejected were mail received
- for them. Implementations generally SHOULD be more aggressive about
- address verification in the case of VRFY than in the case of RCPT,
- even if it takes a little longer to do so.
-
-
-
-
-
-Klensin Standards Track [Page 25]
-
-RFC 5321 SMTP October 2008
-
-
-3.5.4. Semantics and Applications of EXPN
-
- EXPN is often very useful in debugging and understanding problems
- with mailing lists and multiple-target-address aliases. Some systems
- have attempted to use source expansion of mailing lists as a means of
- eliminating duplicates. The propagation of aliasing systems with
- mail on the Internet for hosts (typically with MX and CNAME DNS
- records), for mailboxes (various types of local host aliases), and in
- various proxying arrangements has made it nearly impossible for these
- strategies to work consistently, and mail systems SHOULD NOT attempt
- them.
-
-3.6. Relaying and Mail Routing
-
-3.6.1. Source Routes and Relaying
-
- In general, the availability of Mail eXchanger records in the domain
- name system (RFC 1035 [2], RFC 974 [12]) makes the use of explicit
- source routes in the Internet mail system unnecessary. Many
- historical problems with the interpretation of explicit source routes
- have made their use undesirable. SMTP clients SHOULD NOT generate
- explicit source routes except under unusual circumstances. SMTP
- servers MAY decline to act as mail relays or to accept addresses that
- specify source routes. When route information is encountered, SMTP
- servers MAY ignore the route information and simply send to the final
- destination specified as the last element in the route and SHOULD do
- so. There has been an invalid practice of using names that do not
- appear in the DNS as destination names, with the senders counting on
- the intermediate hosts specified in source routing to resolve any
- problems. If source routes are stripped, this practice will cause
- failures. This is one of several reasons why SMTP clients MUST NOT
- generate invalid source routes or depend on serial resolution of
- names.
-
- When source routes are not used, the process described in RFC 821 for
- constructing a reverse-path from the forward-path is not applicable
- and the reverse-path at the time of delivery will simply be the
- address that appeared in the MAIL command.
-
-3.6.2. Mail eXchange Records and Relaying
-
- A relay SMTP server is usually the target of a DNS MX record that
- designates it, rather than the final delivery system. The relay
- server may accept or reject the task of relaying the mail in the same
- way it accepts or rejects mail for a local user. If it accepts the
- task, it then becomes an SMTP client, establishes a transmission
- channel to the next SMTP server specified in the DNS (according to
- the rules in Section 5), and sends it the mail. If it declines to
-
-
-
-Klensin Standards Track [Page 26]
-
-RFC 5321 SMTP October 2008
-
-
- relay mail to a particular address for policy reasons, a 550 response
- SHOULD be returned.
-
- This specification does not deal with the verification of return
- paths for use in delivery notifications. Recent work, such as that
- on SPF [29] and DKIM [30] [31], has been done to provide ways to
- ascertain that an address is valid or belongs to the person who
- actually sent the message. A server MAY attempt to verify the return
- path before using its address for delivery notifications, but methods
- of doing so are not defined here nor is any particular method
- recommended at this time.
-
-3.6.3. Message Submission Servers as Relays
-
- Many mail-sending clients exist, especially in conjunction with
- facilities that receive mail via POP3 or IMAP, that have limited
- capability to support some of the requirements of this specification,
- such as the ability to queue messages for subsequent delivery
- attempts. For these clients, it is common practice to make private
- arrangements to send all messages to a single server for processing
- and subsequent distribution. SMTP, as specified here, is not ideally
- suited for this role. A standardized mail submission protocol has
- been developed that is gradually superseding practices based on SMTP
- (see RFC 4409 [18]). In any event, because these arrangements are
- private and fall outside the scope of this specification, they are
- not described here.
-
- It is important to note that MX records can point to SMTP servers
- that act as gateways into other environments, not just SMTP relays
- and final delivery systems; see Sections 3.7 and 5.
-
- If an SMTP server has accepted the task of relaying the mail and
- later finds that the destination is incorrect or that the mail cannot
- be delivered for some other reason, then it MUST construct an
- "undeliverable mail" notification message and send it to the
- originator of the undeliverable mail (as indicated by the reverse-
- path). Formats specified for non-delivery reports by other standards
- (see, for example, RFC 3461 [32] and RFC 3464 [33]) SHOULD be used if
- possible.
-
- This notification message must be from the SMTP server at the relay
- host or the host that first determines that delivery cannot be
- accomplished. Of course, SMTP servers MUST NOT send notification
- messages about problems transporting notification messages. One way
- to prevent loops in error reporting is to specify a null reverse-path
- in the MAIL command of a notification message. When such a message
- is transmitted, the reverse-path MUST be set to null (see
-
-
-
-
-Klensin Standards Track [Page 27]
-
-RFC 5321 SMTP October 2008
-
-
- Section 4.5.5 for additional discussion). A MAIL command with a null
- reverse-path appears as follows:
-
- MAIL FROM:<>
-
- As discussed in Section 6.4, a relay SMTP has no need to inspect or
- act upon the header section or body of the message data and MUST NOT
- do so except to add its own "Received:" header field (Section 4.4)
- and, optionally, to attempt to detect looping in the mail system (see
- Section 6.3). Of course, this prohibition also applies to any
- modifications of these header fields or text (see also Section 7.9).
-
-3.7. Mail Gatewaying
-
- While the relay function discussed above operates within the Internet
- SMTP transport service environment, MX records or various forms of
- explicit routing may require that an intermediate SMTP server perform
- a translation function between one transport service and another. As
- discussed in Section 2.3.10, when such a system is at the boundary
- between two transport service environments, we refer to it as a
- "gateway" or "gateway SMTP".
-
- Gatewaying mail between different mail environments, such as
- different mail formats and protocols, is complex and does not easily
- yield to standardization. However, some general requirements may be
- given for a gateway between the Internet and another mail
- environment.
-
-3.7.1. Header Fields in Gatewaying
-
- Header fields MAY be rewritten when necessary as messages are
- gatewayed across mail environment boundaries. This may involve
- inspecting the message body or interpreting the local-part of the
- destination address in spite of the prohibitions in Section 6.4.
-
- Other mail systems gatewayed to the Internet often use a subset of
- the RFC 822 header section or provide similar functionality with a
- different syntax, but some of these mail systems do not have an
- equivalent to the SMTP envelope. Therefore, when a message leaves
- the Internet environment, it may be necessary to fold the SMTP
- envelope information into the message header section. A possible
- solution would be to create new header fields to carry the envelope
- information (e.g., "X-SMTP-MAIL:" and "X-SMTP-RCPT:"); however, this
- would require changes in mail programs in foreign environments and
- might risk disclosure of private information (see Section 7.2).
-
-
-
-
-
-
-Klensin Standards Track [Page 28]
-
-RFC 5321 SMTP October 2008
-
-
-3.7.2. Received Lines in Gatewaying
-
- When forwarding a message into or out of the Internet environment, a
- gateway MUST prepend a Received: line, but it MUST NOT alter in any
- way a Received: line that is already in the header section.
-
- "Received:" header fields of messages originating from other
- environments may not conform exactly to this specification. However,
- the most important use of Received: lines is for debugging mail
- faults, and this debugging can be severely hampered by well-meaning
- gateways that try to "fix" a Received: line. As another consequence
- of trace header fields arising in non-SMTP environments, receiving
- systems MUST NOT reject mail based on the format of a trace header
- field and SHOULD be extremely robust in the light of unexpected
- information or formats in those header fields.
-
- The gateway SHOULD indicate the environment and protocol in the "via"
- clauses of Received header field(s) that it supplies.
-
-3.7.3. Addresses in Gatewaying
-
- From the Internet side, the gateway SHOULD accept all valid address
- formats in SMTP commands and in the RFC 822 header section, and all
- valid RFC 822 messages. Addresses and header fields generated by
- gateways MUST conform to applicable standards (including this one and
- RFC 5322 [4]). Gateways are, of course, subject to the same rules
- for handling source routes as those described for other SMTP systems
- in Section 3.3.
-
-3.7.4. Other Header Fields in Gatewaying
-
- The gateway MUST ensure that all header fields of a message that it
- forwards into the Internet mail environment meet the requirements for
- Internet mail. In particular, all addresses in "From:", "To:",
- "Cc:", etc., header fields MUST be transformed (if necessary) to
- satisfy the standard header syntax of RFC 5322 [4], MUST reference
- only fully-qualified domain names, and MUST be effective and useful
- for sending replies. The translation algorithm used to convert mail
- from the Internet protocols to another environment's protocol SHOULD
- ensure that error messages from the foreign mail environment are
- delivered to the reverse-path from the SMTP envelope, not to an
- address in the "From:", "Sender:", or similar header fields of the
- message.
-
-
-
-
-
-
-
-
-Klensin Standards Track [Page 29]
-
-RFC 5321 SMTP October 2008
-
-
-3.7.5. Envelopes in Gatewaying
-
- Similarly, when forwarding a message from another environment into
- the Internet, the gateway SHOULD set the envelope return path in
- accordance with an error message return address, if supplied by the
- foreign environment. If the foreign environment has no equivalent
- concept, the gateway must select and use a best approximation, with
- the message originator's address as the default of last resort.
-
-3.8. Terminating Sessions and Connections
-
- An SMTP connection is terminated when the client sends a QUIT
- command. The server responds with a positive reply code, after which
- it closes the connection.
-
- An SMTP server MUST NOT intentionally close the connection under
- normal operational circumstances (see Section 7.8) except:
-
- o After receiving a QUIT command and responding with a 221 reply.
-
- o After detecting the need to shut down the SMTP service and
- returning a 421 response code. This response code can be issued
- after the server receives any command or, if necessary,
- asynchronously from command receipt (on the assumption that the
- client will receive it after the next command is issued).
-
- o After a timeout, as specified in Section 4.5.3.2, occurs waiting
- for the client to send a command or data.
-
- In particular, a server that closes connections in response to
- commands that are not understood is in violation of this
- specification. Servers are expected to be tolerant of unknown
- commands, issuing a 500 reply and awaiting further instructions from
- the client.
-
- An SMTP server that is forcibly shut down via external means SHOULD
- attempt to send a line containing a 421 response code to the SMTP
- client before exiting. The SMTP client will normally read the 421
- response code after sending its next command.
-
- SMTP clients that experience a connection close, reset, or other
- communications failure due to circumstances not under their control
- (in violation of the intent of this specification but sometimes
- unavoidable) SHOULD, to maintain the robustness of the mail system,
- treat the mail transaction as if a 451 response had been received and
- act accordingly.
-
-
-
-
-
-Klensin Standards Track [Page 30]
-
-RFC 5321 SMTP October 2008
-
-
-3.9. Mailing Lists and Aliases
-
- An SMTP-capable host SHOULD support both the alias and the list
- models of address expansion for multiple delivery. When a message is
- delivered or forwarded to each address of an expanded list form, the
- return address in the envelope ("MAIL FROM:") MUST be changed to be
- the address of a person or other entity who administers the list.
- However, in this case, the message header section (RFC 5322 [4]) MUST
- be left unchanged; in particular, the "From" field of the header
- section is unaffected.
-
- An important mail facility is a mechanism for multi-destination
- delivery of a single message, by transforming (or "expanding" or
- "exploding") a pseudo-mailbox address into a list of destination
- mailbox addresses. When a message is sent to such a pseudo-mailbox
- (sometimes called an "exploder"), copies are forwarded or
- redistributed to each mailbox in the expanded list. Servers SHOULD
- simply utilize the addresses on the list; application of heuristics
- or other matching rules to eliminate some addresses, such as that of
- the originator, is strongly discouraged. We classify such a pseudo-
- mailbox as an "alias" or a "list", depending upon the expansion
- rules.
-
-3.9.1. Alias
-
- To expand an alias, the recipient mailer simply replaces the pseudo-
- mailbox address in the envelope with each of the expanded addresses
- in turn; the rest of the envelope and the message body are left
- unchanged. The message is then delivered or forwarded to each
- expanded address.
-
-3.9.2. List
-
- A mailing list may be said to operate by "redistribution" rather than
- by "forwarding". To expand a list, the recipient mailer replaces the
- pseudo-mailbox address in the envelope with each of the expanded
- addresses in turn. The return (backward-pointing) address in the
- envelope is changed so that all error messages generated by the final
- deliveries will be returned to a list administrator, not to the
- message originator, who generally has no control over the contents of
- the list and will typically find error messages annoying. Note that
- the key difference between handling aliases (Section 3.9.1) and
- forwarding (this subsection) is the change to the backward-pointing
- address in this case. When a list constrains its processing to the
- very limited set of modifications and actions described here, it is
- attempting to emulate an MTA; such lists can be treated as a
- continuation in email transit.
-
-
-
-
-Klensin Standards Track [Page 31]
-
-RFC 5321 SMTP October 2008
-
-
- There exist mailing lists that perform additional, sometimes
- extensive, modifications to a message and its envelope. Such mailing
- lists need to be viewed as full MUAs, which accept a delivery and
- post a new message.
-
-4. The SMTP Specifications
-
-4.1. SMTP Commands
-
-4.1.1. Command Semantics and Syntax
-
- The SMTP commands define the mail transfer or the mail system
- function requested by the user. SMTP commands are character strings
- terminated by . The commands themselves are alphabetic
- characters terminated by if parameters follow and
- otherwise. (In the interest of improved interoperability, SMTP
- receivers SHOULD tolerate trailing white space before the terminating
- .) The syntax of the local part of a mailbox MUST conform to
- receiver site conventions and the syntax specified in Section 4.1.2.
- The SMTP commands are discussed below. The SMTP replies are
- discussed in Section 4.2.
-
- A mail transaction involves several data objects that are
- communicated as arguments to different commands. The reverse-path is
- the argument of the MAIL command, the forward-path is the argument of
- the RCPT command, and the mail data is the argument of the DATA
- command. These arguments or data objects must be transmitted and
- held, pending the confirmation communicated by the end of mail data
- indication that finalizes the transaction. The model for this is
- that distinct buffers are provided to hold the types of data objects;
- that is, there is a reverse-path buffer, a forward-path buffer, and a
- mail data buffer. Specific commands cause information to be appended
- to a specific buffer, or cause one or more buffers to be cleared.
-
- Several commands (RSET, DATA, QUIT) are specified as not permitting
- parameters. In the absence of specific extensions offered by the
- server and accepted by the client, clients MUST NOT send such
- parameters and servers SHOULD reject commands containing them as
- having invalid syntax.
-
-4.1.1.1. Extended HELLO (EHLO) or HELLO (HELO)
-
- These commands are used to identify the SMTP client to the SMTP
- server. The argument clause contains the fully-qualified domain name
- of the SMTP client, if one is available. In situations in which the
- SMTP client system does not have a meaningful domain name (e.g., when
- its address is dynamically allocated and no reverse mapping record is
-
-
-
-
-Klensin Standards Track [Page 32]
-
-RFC 5321 SMTP October 2008
-
-
- available), the client SHOULD send an address literal (see
- Section 4.1.3).
-
- RFC 2821, and some earlier informal practices, encouraged following
- the literal by information that would help to identify the client
- system. That convention was not widely supported, and many SMTP
- servers considered it an error. In the interest of interoperability,
- it is probably wise for servers to be prepared for this string to
- occur, but SMTP clients SHOULD NOT send it.
-
- The SMTP server identifies itself to the SMTP client in the
- connection greeting reply and in the response to this command.
-
- A client SMTP SHOULD start an SMTP session by issuing the EHLO
- command. If the SMTP server supports the SMTP service extensions, it
- will give a successful response, a failure response, or an error
- response. If the SMTP server, in violation of this specification,
- does not support any SMTP service extensions, it will generate an
- error response. Older client SMTP systems MAY, as discussed above,
- use HELO (as specified in RFC 821) instead of EHLO, and servers MUST
- support the HELO command and reply properly to it. In any event, a
- client MUST issue HELO or EHLO before starting a mail transaction.
-
- These commands, and a "250 OK" reply to one of them, confirm that
- both the SMTP client and the SMTP server are in the initial state,
- that is, there is no transaction in progress and all state tables and
- buffers are cleared.
-
- Syntax:
-
- ehlo = "EHLO" SP ( Domain / address-literal ) CRLF
-
- helo = "HELO" SP Domain CRLF
-
- Normally, the response to EHLO will be a multiline reply. Each line
- of the response contains a keyword and, optionally, one or more
- parameters. Following the normal syntax for multiline replies, these
- keywords follow the code (250) and a hyphen for all but the last
- line, and the code and a space for the last line. The syntax for a
- positive response, using the ABNF notation and terminal symbols of
- RFC 5234 [7], is:
-
- ehlo-ok-rsp = ( "250" SP Domain [ SP ehlo-greet ] CRLF )
- / ( "250-" Domain [ SP ehlo-greet ] CRLF
- *( "250-" ehlo-line CRLF )
- "250" SP ehlo-line CRLF )
-
-
-
-
-
-Klensin Standards Track [Page 33]
-
-RFC 5321 SMTP October 2008
-
-
- ehlo-greet = 1*(%d0-9 / %d11-12 / %d14-127)
- ; string of any characters other than CR or LF
-
- ehlo-line = ehlo-keyword *( SP ehlo-param )
-
- ehlo-keyword = (ALPHA / DIGIT) *(ALPHA / DIGIT / "-")
- ; additional syntax of ehlo-params depends on
- ; ehlo-keyword
-
- ehlo-param = 1*(%d33-126)
- ; any CHAR excluding and all
- ; control characters (US-ASCII 0-31 and 127
- ; inclusive)
-
- Although EHLO keywords may be specified in upper, lower, or mixed
- case, they MUST always be recognized and processed in a case-
- insensitive manner. This is simply an extension of practices
- specified in RFC 821 and Section 2.4.
-
- The EHLO response MUST contain keywords (and associated parameters if
- required) for all commands not listed as "required" in Section 4.5.1
- excepting only private-use commands as described in Section 4.1.5.
- Private-use commands MAY be listed.
-
-4.1.1.2. MAIL (MAIL)
-
- This command is used to initiate a mail transaction in which the mail
- data is delivered to an SMTP server that may, in turn, deliver it to
- one or more mailboxes or pass it on to another system (possibly using
- SMTP). The argument clause contains a reverse-path and may contain
- optional parameters. In general, the MAIL command may be sent only
- when no mail transaction is in progress, see Section 4.1.4.
-
- The reverse-path consists of the sender mailbox. Historically, that
- mailbox might optionally have been preceded by a list of hosts, but
- that behavior is now deprecated (see Appendix C). In some types of
- reporting messages for which a reply is likely to cause a mail loop
- (for example, mail delivery and non-delivery notifications), the
- reverse-path may be null (see Section 3.6).
-
- This command clears the reverse-path buffer, the forward-path buffer,
- and the mail data buffer, and it inserts the reverse-path information
- from its argument clause into the reverse-path buffer.
-
- If service extensions were negotiated, the MAIL command may also
- carry parameters associated with a particular service extension.
-
-
-
-
-
-Klensin Standards Track [Page 34]
-
-RFC 5321 SMTP October 2008
-
-
- Syntax:
-
- mail = "MAIL FROM:" Reverse-path
- [SP Mail-parameters] CRLF
-
-4.1.1.3. RECIPIENT (RCPT)
-
- This command is used to identify an individual recipient of the mail
- data; multiple recipients are specified by multiple uses of this
- command. The argument clause contains a forward-path and may contain
- optional parameters.
-
- The forward-path normally consists of the required destination
- mailbox. Sending systems SHOULD NOT generate the optional list of
- hosts known as a source route. Receiving systems MUST recognize
- source route syntax but SHOULD strip off the source route
- specification and utilize the domain name associated with the mailbox
- as if the source route had not been provided.
-
- Similarly, relay hosts SHOULD strip or ignore source routes, and
- names MUST NOT be copied into the reverse-path. When mail reaches
- its ultimate destination (the forward-path contains only a
- destination mailbox), the SMTP server inserts it into the destination
- mailbox in accordance with its host mail conventions.
-
- This command appends its forward-path argument to the forward-path
- buffer; it does not change the reverse-path buffer nor the mail data
- buffer.
-
- For example, mail received at relay host xyz.com with envelope
- commands
-
- MAIL FROM:
- RCPT TO:<@hosta.int,@jkl.org:userc@d.bar.org>
-
- will normally be sent directly on to host d.bar.org with envelope
- commands
-
- MAIL FROM:
- RCPT TO:
-
- As provided in Appendix C, xyz.com MAY also choose to relay the
- message to hosta.int, using the envelope commands
-
- MAIL FROM:
- RCPT TO:<@hosta.int,@jkl.org:userc@d.bar.org>
-
-
-
-
-
-Klensin Standards Track [Page 35]
-
-RFC 5321 SMTP October 2008
-
-
- or to jkl.org, using the envelope commands
-
- MAIL FROM:
- RCPT TO:<@jkl.org:userc@d.bar.org>
-
- Attempting to use relaying this way is now strongly discouraged.
- Since hosts are not required to relay mail at all, xyz.com MAY also
- reject the message entirely when the RCPT command is received, using
- a 550 code (since this is a "policy reason").
-
- If service extensions were negotiated, the RCPT command may also
- carry parameters associated with a particular service extension
- offered by the server. The client MUST NOT transmit parameters other
- than those associated with a service extension offered by the server
- in its EHLO response.
-
- Syntax:
-
- rcpt = "RCPT TO:" ( "" / "" /
- Forward-path ) [SP Rcpt-parameters] CRLF
-
- Note that, in a departure from the usual rules for
- local-parts, the "Postmaster" string shown above is
- treated as case-insensitive.
-
-4.1.1.4. DATA (DATA)
-
- The receiver normally sends a 354 response to DATA, and then treats
- the lines (strings ending in sequences, as described in
- Section 2.3.7) following the command as mail data from the sender.
- This command causes the mail data to be appended to the mail data
- buffer. The mail data may contain any of the 128 ASCII character
- codes, although experience has indicated that use of control
- characters other than SP, HT, CR, and LF may cause problems and
- SHOULD be avoided when possible.
-
- The mail data are terminated by a line containing only a period, that
- is, the character sequence ".", where the first is
- actually the terminator of the previous line (see Section 4.5.2).
- This is the end of mail data indication. The first of this
- terminating sequence is also the that ends the final line of
- the data (message text) or, if there was no mail data, ends the DATA
- command itself (the "no mail data" case does not conform to this
- specification since it would require that neither the trace header
- fields required by this specification nor the message header section
- required by RFC 5322 [4] be transmitted). An extra MUST NOT
- be added, as that would cause an empty line to be added to the
- message. The only exception to this rule would arise if the message
-
-
-
-Klensin Standards Track [Page 36]
-
-RFC 5321 SMTP October 2008
-
-
- body were passed to the originating SMTP-sender with a final "line"
- that did not end in ; in that case, the originating SMTP system
- MUST either reject the message as invalid or add in order to
- have the receiving SMTP server recognize the "end of data" condition.
-
- The custom of accepting lines ending only in , as a concession to
- non-conforming behavior on the part of some UNIX systems, has proven
- to cause more interoperability problems than it solves, and SMTP
- server systems MUST NOT do this, even in the name of improved
- robustness. In particular, the sequence "." (bare line
- feeds, without carriage returns) MUST NOT be treated as equivalent to
- . as the end of mail data indication.
-
- Receipt of the end of mail data indication requires the server to
- process the stored mail transaction information. This processing
- consumes the information in the reverse-path buffer, the forward-path
- buffer, and the mail data buffer, and on the completion of this
- command these buffers are cleared. If the processing is successful,
- the receiver MUST send an OK reply. If the processing fails, the
- receiver MUST send a failure reply. The SMTP model does not allow
- for partial failures at this point: either the message is accepted by
- the server for delivery and a positive response is returned or it is
- not accepted and a failure reply is returned. In sending a positive
- "250 OK" completion reply to the end of data indication, the receiver
- takes full responsibility for the message (see Section 6.1). Errors
- that are diagnosed subsequently MUST be reported in a mail message,
- as discussed in Section 4.4.
-
- When the SMTP server accepts a message either for relaying or for
- final delivery, it inserts a trace record (also referred to
- interchangeably as a "time stamp line" or "Received" line) at the top
- of the mail data. This trace record indicates the identity of the
- host that sent the message, the identity of the host that received
- the message (and is inserting this time stamp), and the date and time
- the message was received. Relayed messages will have multiple time
- stamp lines. Details for formation of these lines, including their
- syntax, is specified in Section 4.4.
-
- Additional discussion about the operation of the DATA command appears
- in Section 3.3.
-
- Syntax:
-
- data = "DATA" CRLF
-
-
-
-
-
-
-
-Klensin Standards Track [Page 37]
-
-RFC 5321 SMTP October 2008
-
-
-4.1.1.5. RESET (RSET)
-
- This command specifies that the current mail transaction will be
- aborted. Any stored sender, recipients, and mail data MUST be
- discarded, and all buffers and state tables cleared. The receiver
- MUST send a "250 OK" reply to a RSET command with no arguments. A
- reset command may be issued by the client at any time. It is
- effectively equivalent to a NOOP (i.e., it has no effect) if issued
- immediately after EHLO, before EHLO is issued in the session, after
- an end of data indicator has been sent and acknowledged, or
- immediately before a QUIT. An SMTP server MUST NOT close the
- connection as the result of receiving a RSET; that action is reserved
- for QUIT (see Section 4.1.1.10).
-
- Since EHLO implies some additional processing and response by the
- server, RSET will normally be more efficient than reissuing that
- command, even though the formal semantics are the same.
-
- There are circumstances, contrary to the intent of this
- specification, in which an SMTP server may receive an indication that
- the underlying TCP connection has been closed or reset. To preserve
- the robustness of the mail system, SMTP servers SHOULD be prepared
- for this condition and SHOULD treat it as if a QUIT had been received
- before the connection disappeared.
-
- Syntax:
-
- rset = "RSET" CRLF
-
-4.1.1.6. VERIFY (VRFY)
-
- This command asks the receiver to confirm that the argument
- identifies a user or mailbox. If it is a user name, information is
- returned as specified in Section 3.5.
-
- This command has no effect on the reverse-path buffer, the forward-
- path buffer, or the mail data buffer.
-
- Syntax:
-
- vrfy = "VRFY" SP String CRLF
-
-
-
-
-
-
-
-
-
-
-Klensin Standards Track [Page 38]
-
-RFC 5321 SMTP October 2008
-
-
-4.1.1.7. EXPAND (EXPN)
-
- This command asks the receiver to confirm that the argument
- identifies a mailing list, and if so, to return the membership of
- that list. If the command is successful, a reply is returned
- containing information as described in Section 3.5. This reply will
- have multiple lines except in the trivial case of a one-member list.
-
- This command has no effect on the reverse-path buffer, the forward-
- path buffer, or the mail data buffer, and it may be issued at any
- time.
-
- Syntax:
-
- expn = "EXPN" SP String CRLF
-
-4.1.1.8. HELP (HELP)
-
- This command causes the server to send helpful information to the
- client. The command MAY take an argument (e.g., any command name)
- and return more specific information as a response.
-
- This command has no effect on the reverse-path buffer, the forward-
- path buffer, or the mail data buffer, and it may be issued at any
- time.
-
- SMTP servers SHOULD support HELP without arguments and MAY support it
- with arguments.
-
- Syntax:
-
- help = "HELP" [ SP String ] CRLF
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Klensin Standards Track [Page 39]
-
-RFC 5321 SMTP October 2008
-
-
-4.1.1.9. NOOP (NOOP)
-
- This command does not affect any parameters or previously entered
- commands. It specifies no action other than that the receiver send a
- "250 OK" reply.
-
- This command has no effect on the reverse-path buffer, the forward-
- path buffer, or the mail data buffer, and it may be issued at any
- time. If a parameter string is specified, servers SHOULD ignore it.
-
- Syntax:
-
- noop = "NOOP" [ SP String ] CRLF
-
-4.1.1.10. QUIT (QUIT)
-
- This command specifies that the receiver MUST send a "221 OK" reply,
- and then close the transmission channel.
-
- The receiver MUST NOT intentionally close the transmission channel
- until it receives and replies to a QUIT command (even if there was an
- error). The sender MUST NOT intentionally close the transmission
- channel until it sends a QUIT command, and it SHOULD wait until it
- receives the reply (even if there was an error response to a previous
- command). If the connection is closed prematurely due to violations
- of the above or system or network failure, the server MUST cancel any
- pending transaction, but not undo any previously completed
- transaction, and generally MUST act as if the command or transaction
- in progress had received a temporary error (i.e., a 4yz response).
-
- The QUIT command may be issued at any time. Any current uncompleted
- mail transaction will be aborted.
-
- Syntax:
-
- quit = "QUIT" CRLF
-
-4.1.1.11. Mail-Parameter and Rcpt-Parameter Error Responses
-
- If the server SMTP does not recognize or cannot implement one or more
- of the parameters associated with a particular MAIL FROM or RCPT TO
- command, it will return code 555.
-
- If, for some reason, the server is temporarily unable to accommodate
- one or more of the parameters associated with a MAIL FROM or RCPT TO
- command, and if the definition of the specific parameter does not
- mandate the use of another code, it should return code 455.
-
-
-
-
-Klensin Standards Track [Page 40]
-
-RFC 5321 SMTP October 2008
-
-
- Errors specific to particular parameters and their values will be
- specified in the parameter's defining RFC.
-
-4.1.2. Command Argument Syntax
-
- The syntax of the argument clauses of the above commands (using the
- syntax specified in RFC 5234 [7] where applicable) is given below.
- Some of the productions given below are used only in conjunction with
- source routes as described in Appendix C. Terminals not defined in
- this document, such as ALPHA, DIGIT, SP, CR, LF, CRLF, are as defined
- in the "core" syntax in Section 6 of RFC 5234 [7] or in the message
- format syntax in RFC 5322 [4].
-
- Reverse-path = Path / "<>"
-
- Forward-path = Path
-
- Path = "<" [ A-d-l ":" ] Mailbox ">"
-
- A-d-l = At-domain *( "," At-domain )
- ; Note that this form, the so-called "source
- ; route", MUST BE accepted, SHOULD NOT be
- ; generated, and SHOULD be ignored.
-
- At-domain = "@" Domain
-
- Mail-parameters = esmtp-param *(SP esmtp-param)
-
- Rcpt-parameters = esmtp-param *(SP esmtp-param)
-
- esmtp-param = esmtp-keyword ["=" esmtp-value]
-
- esmtp-keyword = (ALPHA / DIGIT) *(ALPHA / DIGIT / "-")
-
- esmtp-value = 1*(%d33-60 / %d62-126)
- ; any CHAR excluding "=", SP, and control
- ; characters. If this string is an email address,
- ; i.e., a Mailbox, then the "xtext" syntax [32]
- ; SHOULD be used.
-
- Keyword = Ldh-str
-
- Argument = Atom
-
- Domain = sub-domain *("." sub-domain)
-
-
-
-
-
-
-Klensin Standards Track [Page 41]
-
-RFC 5321 SMTP October 2008
-
-
- sub-domain = Let-dig [Ldh-str]
-
- Let-dig = ALPHA / DIGIT
-
- Ldh-str = *( ALPHA / DIGIT / "-" ) Let-dig
-
- address-literal = "[" ( IPv4-address-literal /
- IPv6-address-literal /
- General-address-literal ) "]"
- ; See Section 4.1.3
-
- Mailbox = Local-part "@" ( Domain / address-literal )
-
- Local-part = Dot-string / Quoted-string
- ; MAY be case-sensitive
-
-
- Dot-string = Atom *("." Atom)
-
- Atom = 1*atext
-
- Quoted-string = DQUOTE *QcontentSMTP DQUOTE
-
- QcontentSMTP = qtextSMTP / quoted-pairSMTP
-
- quoted-pairSMTP = %d92 %d32-126
- ; i.e., backslash followed by any ASCII
- ; graphic (including itself) or SPace
-
- qtextSMTP = %d32-33 / %d35-91 / %d93-126
- ; i.e., within a quoted string, any
- ; ASCII graphic or space is permitted
- ; without blackslash-quoting except
- ; double-quote and the backslash itself.
-
- String = Atom / Quoted-string
-
- While the above definition for Local-part is relatively permissive,
- for maximum interoperability, a host that expects to receive mail
- SHOULD avoid defining mailboxes where the Local-part requires (or
- uses) the Quoted-string form or where the Local-part is case-
- sensitive. For any purposes that require generating or comparing
- Local-parts (e.g., to specific mailbox names), all quoted forms MUST
- be treated as equivalent, and the sending system SHOULD transmit the
- form that uses the minimum quoting possible.
-
- Systems MUST NOT define mailboxes in such a way as to require the use
- in SMTP of non-ASCII characters (octets with the high order bit set
-
-
-
-Klensin Standards Track [Page 42]
-
-RFC 5321 SMTP October 2008
-
-
- to one) or ASCII "control characters" (decimal value 0-31 and 127).
- These characters MUST NOT be used in MAIL or RCPT commands or other
- commands that require mailbox names.
-
- Note that the backslash, "\", is a quote character, which is used to
- indicate that the next character is to be used literally (instead of
- its normal interpretation). For example, "Joe\,Smith" indicates a
- single nine-character user name string with the comma being the
- fourth character of that string.
-
- To promote interoperability and consistent with long-standing
- guidance about conservative use of the DNS in naming and applications
- (e.g., see Section 2.3.1 of the base DNS document, RFC 1035 [2]),
- characters outside the set of alphabetic characters, digits, and
- hyphen MUST NOT appear in domain name labels for SMTP clients or
- servers. In particular, the underscore character is not permitted.
- SMTP servers that receive a command in which invalid character codes
- have been employed, and for which there are no other reasons for
- rejection, MUST reject that command with a 501 response (this rule,
- like others, could be overridden by appropriate SMTP extensions).
-
-4.1.3. Address Literals
-
- Sometimes a host is not known to the domain name system and
- communication (and, in particular, communication to report and repair
- the error) is blocked. To bypass this barrier, a special literal
- form of the address is allowed as an alternative to a domain name.
- For IPv4 addresses, this form uses four small decimal integers
- separated by dots and enclosed by brackets such as [123.255.37.2],
- which indicates an (IPv4) Internet Address in sequence-of-octets
- form. For IPv6 and other forms of addressing that might eventually
- be standardized, the form consists of a standardized "tag" that
- identifies the address syntax, a colon, and the address itself, in a
- format specified as part of the relevant standards (i.e., RFC 4291
- [8] for IPv6).
-
- Specifically:
-
- IPv4-address-literal = Snum 3("." Snum)
-
- IPv6-address-literal = "IPv6:" IPv6-addr
-
- General-address-literal = Standardized-tag ":" 1*dcontent
-
- Standardized-tag = Ldh-str
- ; Standardized-tag MUST be specified in a
- ; Standards-Track RFC and registered with IANA
-
-
-
-
-Klensin Standards Track [Page 43]
-
-RFC 5321 SMTP October 2008
-
-
- dcontent = %d33-90 / ; Printable US-ASCII
- %d94-126 ; excl. "[", "\", "]"
-
- Snum = 1*3DIGIT
- ; representing a decimal integer
- ; value in the range 0 through 255
-
- IPv6-addr = IPv6-full / IPv6-comp / IPv6v4-full / IPv6v4-comp
-
- IPv6-hex = 1*4HEXDIG
-
- IPv6-full = IPv6-hex 7(":" IPv6-hex)
-
- IPv6-comp = [IPv6-hex *5(":" IPv6-hex)] "::"
- [IPv6-hex *5(":" IPv6-hex)]
- ; The "::" represents at least 2 16-bit groups of
- ; zeros. No more than 6 groups in addition to the
- ; "::" may be present.
-
- IPv6v4-full = IPv6-hex 5(":" IPv6-hex) ":" IPv4-address-literal
-
- IPv6v4-comp = [IPv6-hex *3(":" IPv6-hex)] "::"
- [IPv6-hex *3(":" IPv6-hex) ":"]
- IPv4-address-literal
- ; The "::" represents at least 2 16-bit groups of
- ; zeros. No more than 4 groups in addition to the
- ; "::" and IPv4-address-literal may be present.
-
-4.1.4. Order of Commands
-
- There are restrictions on the order in which these commands may be
- used.
-
- A session that will contain mail transactions MUST first be
- initialized by the use of the EHLO command. An SMTP server SHOULD
- accept commands for non-mail transactions (e.g., VRFY or EXPN)
- without this initialization.
-
- An EHLO command MAY be issued by a client later in the session. If
- it is issued after the session begins and the EHLO command is
- acceptable to the SMTP server, the SMTP server MUST clear all buffers
- and reset the state exactly as if a RSET command had been issued. In
- other words, the sequence of RSET followed immediately by EHLO is
- redundant, but not harmful other than in the performance cost of
- executing unnecessary commands.
-
- If the EHLO command is not acceptable to the SMTP server, 501, 500,
- 502, or 550 failure replies MUST be returned as appropriate. The
-
-
-
-Klensin Standards Track [Page 44]
-
-RFC 5321 SMTP October 2008
-
-
- SMTP server MUST stay in the same state after transmitting these
- replies that it was in before the EHLO was received.
-
- The SMTP client MUST, if possible, ensure that the domain parameter
- to the EHLO command is a primary host name as specified for this
- command in Section 2.3.5. If this is not possible (e.g., when the
- client's address is dynamically assigned and the client does not have
- an obvious name), an address literal SHOULD be substituted for the
- domain name.
-
- An SMTP server MAY verify that the domain name argument in the EHLO
- command actually corresponds to the IP address of the client.
- However, if the verification fails, the server MUST NOT refuse to
- accept a message on that basis. Information captured in the
- verification attempt is for logging and tracing purposes. Note that
- this prohibition applies to the matching of the parameter to its IP
- address only; see Section 7.9 for a more extensive discussion of
- rejecting incoming connections or mail messages.
-
- The NOOP, HELP, EXPN, VRFY, and RSET commands can be used at any time
- during a session, or without previously initializing a session. SMTP
- servers SHOULD process these normally (that is, not return a 503
- code) even if no EHLO command has yet been received; clients SHOULD
- open a session with EHLO before sending these commands.
-
- If these rules are followed, the example in RFC 821 that shows "550
- access denied to you" in response to an EXPN command is incorrect
- unless an EHLO command precedes the EXPN or the denial of access is
- based on the client's IP address or other authentication or
- authorization-determining mechanisms.
-
- The MAIL command (or the obsolete SEND, SOML, or SAML commands)
- begins a mail transaction. Once started, a mail transaction consists
- of a transaction beginning command, one or more RCPT commands, and a
- DATA command, in that order. A mail transaction may be aborted by
- the RSET, a new EHLO, or the QUIT command. There may be zero or more
- transactions in a session. MAIL (or SEND, SOML, or SAML) MUST NOT be
- sent if a mail transaction is already open, i.e., it should be sent
- only if no mail transaction had been started in the session, or if
- the previous one successfully concluded with a successful DATA
- command, or if the previous one was aborted, e.g., with a RSET or new
- EHLO.
-
- If the transaction beginning command argument is not acceptable, a
- 501 failure reply MUST be returned and the SMTP server MUST stay in
- the same state. If the commands in a transaction are out of order to
- the degree that they cannot be processed by the server, a 503 failure
-
-
-
-
-Klensin Standards Track [Page 45]
-
-RFC 5321 SMTP October 2008
-
-
- reply MUST be returned and the SMTP server MUST stay in the same
- state.
-
- The last command in a session MUST be the QUIT command. The QUIT
- command SHOULD be used by the client SMTP to request connection
- closure, even when no session opening command was sent and accepted.
-
-4.1.5. Private-Use Commands
-
- As specified in Section 2.2.2, commands starting in "X" may be used
- by bilateral agreement between the client (sending) and server
- (receiving) SMTP agents. An SMTP server that does not recognize such
- a command is expected to reply with "500 Command not recognized". An
- extended SMTP server MAY list the feature names associated with these
- private commands in the response to the EHLO command.
-
- Commands sent or accepted by SMTP systems that do not start with "X"
- MUST conform to the requirements of Section 2.2.2.
-
-4.2. SMTP Replies
-
- Replies to SMTP commands serve to ensure the synchronization of
- requests and actions in the process of mail transfer and to guarantee
- that the SMTP client always knows the state of the SMTP server.
- Every command MUST generate exactly one reply.
-
- The details of the command-reply sequence are described in
- Section 4.3.
-
- An SMTP reply consists of a three digit number (transmitted as three
- numeric characters) followed by some text unless specified otherwise
- in this document. The number is for use by automata to determine
- what state to enter next; the text is for the human user. The three
- digits contain enough encoded information that the SMTP client need
- not examine the text and may either discard it or pass it on to the
- user, as appropriate. Exceptions are as noted elsewhere in this
- document. In particular, the 220, 221, 251, 421, and 551 reply codes
- are associated with message text that must be parsed and interpreted
- by machines. In the general case, the text may be receiver dependent
- and context dependent, so there are likely to be varying texts for
- each reply code. A discussion of the theory of reply codes is given
- in Section 4.2.1. Formally, a reply is defined to be the sequence: a
- three-digit code, , one line of text, and , or a multiline
- reply (as defined in the same section). Since, in violation of this
- specification, the text is sometimes not sent, clients that do not
- receive it SHOULD be prepared to process the code alone (with or
- without a trailing space character). Only the EHLO, EXPN, and HELP
- commands are expected to result in multiline replies in normal
-
-
-
-Klensin Standards Track [Page 46]
-
-RFC 5321 SMTP October 2008
-
-
- circumstances; however, multiline replies are allowed for any
- command.
-
- In ABNF, server responses are:
-
- Greeting = ( "220 " (Domain / address-literal)
- [ SP textstring ] CRLF ) /
- ( "220-" (Domain / address-literal)
- [ SP textstring ] CRLF
- *( "220-" [ textstring ] CRLF )
- "220" [ SP textstring ] CRLF )
-
- textstring = 1*(%d09 / %d32-126) ; HT, SP, Printable US-ASCII
-
- Reply-line = *( Reply-code "-" [ textstring ] CRLF )
- Reply-code [ SP textstring ] CRLF
-
- Reply-code = %x32-35 %x30-35 %x30-39
-
- where "Greeting" appears only in the 220 response that announces that
- the server is opening its part of the connection. (Other possible
- server responses upon connection follow the syntax of Reply-line.)
-
- An SMTP server SHOULD send only the reply codes listed in this
- document. An SMTP server SHOULD use the text shown in the examples
- whenever appropriate.
-
- An SMTP client MUST determine its actions only by the reply code, not
- by the text (except for the "change of address" 251 and 551 and, if
- necessary, 220, 221, and 421 replies); in the general case, any text,
- including no text at all (although senders SHOULD NOT send bare
- codes), MUST be acceptable. The space (blank) following the reply
- code is considered part of the text. Whenever possible, a receiver-
- SMTP SHOULD test the first digit (severity indication) of the reply
- code.
-
- The list of codes that appears below MUST NOT be construed as
- permanent. While the addition of new codes should be a rare and
- significant activity, with supplemental information in the textual
- part of the response being preferred, new codes may be added as the
- result of new Standards or Standards-Track specifications.
- Consequently, a sender-SMTP MUST be prepared to handle codes not
- specified in this document and MUST do so by interpreting the first
- digit only.
-
- In the absence of extensions negotiated with the client, SMTP servers
- MUST NOT send reply codes whose first digits are other than 2, 3, 4,
-
-
-
-
-Klensin Standards Track [Page 47]
-
-RFC 5321 SMTP October 2008
-
-
- or 5. Clients that receive such out-of-range codes SHOULD normally
- treat them as fatal errors and terminate the mail transaction.
-
-4.2.1. Reply Code Severities and Theory
-
- The three digits of the reply each have a special significance. The
- first digit denotes whether the response is good, bad, or incomplete.
- An unsophisticated SMTP client, or one that receives an unexpected
- code, will be able to determine its next action (proceed as planned,
- redo, retrench, etc.) by examining this first digit. An SMTP client
- that wants to know approximately what kind of error occurred (e.g.,
- mail system error, command syntax error) may examine the second
- digit. The third digit and any supplemental information that may be
- present is reserved for the finest gradation of information.
-
- There are four values for the first digit of the reply code:
-
- 2yz Positive Completion reply
- The requested action has been successfully completed. A new
- request may be initiated.
-
- 3yz Positive Intermediate reply
- The command has been accepted, but the requested action is being
- held in abeyance, pending receipt of further information. The
- SMTP client should send another command specifying this
- information. This reply is used in command sequence groups (i.e.,
- in DATA).
-
- 4yz Transient Negative Completion reply
- The command was not accepted, and the requested action did not
- occur. However, the error condition is temporary, and the action
- may be requested again. The sender should return to the beginning
- of the command sequence (if any). It is difficult to assign a
- meaning to "transient" when two different sites (receiver- and
- sender-SMTP agents) must agree on the interpretation. Each reply
- in this category might have a different time value, but the SMTP
- client SHOULD try again. A rule of thumb to determine whether a
- reply fits into the 4yz or the 5yz category (see below) is that
- replies are 4yz if they can be successful if repeated without any
- change in command form or in properties of the sender or receiver
- (that is, the command is repeated identically and the receiver
- does not put up a new implementation).
-
- 5yz Permanent Negative Completion reply
- The command was not accepted and the requested action did not
- occur. The SMTP client SHOULD NOT repeat the exact request (in
- the same sequence). Even some "permanent" error conditions can be
- corrected, so the human user may want to direct the SMTP client to
-
-
-
-Klensin Standards Track [Page 48]
-
-RFC 5321 SMTP October 2008
-
-
- reinitiate the command sequence by direct action at some point in
- the future (e.g., after the spelling has been changed, or the user
- has altered the account status).
-
- It is worth noting that the file transfer protocol (FTP) [34] uses a
- very similar code architecture and that the SMTP codes are based on
- the FTP model. However, SMTP uses a one-command, one-response model
- (while FTP is asynchronous) and FTP's 1yz codes are not part of the
- SMTP model.
-
- The second digit encodes responses in specific categories:
-
- x0z Syntax: These replies refer to syntax errors, syntactically
- correct commands that do not fit any functional category, and
- unimplemented or superfluous commands.
-
- x1z Information: These are replies to requests for information, such
- as status or help.
-
- x2z Connections: These are replies referring to the transmission
- channel.
-
- x3z Unspecified.
-
- x4z Unspecified.
-
- x5z Mail system: These replies indicate the status of the receiver
- mail system vis-a-vis the requested transfer or other mail system
- action.
-
- The third digit gives a finer gradation of meaning in each category
- specified by the second digit. The list of replies illustrates this.
- Each reply text is recommended rather than mandatory, and may even
- change according to the command with which it is associated. On the
- other hand, the reply codes must strictly follow the specifications
- in this section. Receiver implementations should not invent new
- codes for slightly different situations from the ones described here,
- but rather adapt codes already defined.
-
- For example, a command such as NOOP, whose successful execution does
- not offer the SMTP client any new information, will return a 250
- reply. The reply is 502 when the command requests an unimplemented
- non-site-specific action. A refinement of that is the 504 reply for
- a command that is implemented, but that requests an unimplemented
- parameter.
-
-
-
-
-
-
-Klensin Standards Track [Page 49]
-
-RFC 5321 SMTP October 2008
-
-
- The reply text may be longer than a single line; in these cases the
- complete text must be marked so the SMTP client knows when it can
- stop reading the reply. This requires a special format to indicate a
- multiple line reply.
-
- The format for multiline replies requires that every line, except the
- last, begin with the reply code, followed immediately by a hyphen,
- "-" (also known as minus), followed by text. The last line will
- begin with the reply code, followed immediately by , optionally
- some text, and . As noted above, servers SHOULD send the
- if subsequent text is not sent, but clients MUST be prepared for it
- to be omitted.
-
- For example:
-
- 250-First line
- 250-Second line
- 250-234 Text beginning with numbers
- 250 The last line
-
- In a multiline reply, the reply code on each of the lines MUST be the
- same. It is reasonable for the client to rely on this, so it can
- make processing decisions based on the code in any line, assuming
- that all others will be the same. In a few cases, there is important
- data for the client in the reply "text". The client will be able to
- identify these cases from the current context.
-
-4.2.2. Reply Codes by Function Groups
-
- 500 Syntax error, command unrecognized (This may include errors such
- as command line too long)
-
- 501 Syntax error in parameters or arguments
-
- 502 Command not implemented (see Section 4.2.4)
-
- 503 Bad sequence of commands
-
- 504 Command parameter not implemented
-
-
- 211 System status, or system help reply
-
- 214 Help message (Information on how to use the receiver or the
- meaning of a particular non-standard command; this reply is useful
- only to the human user)
-
-
-
-
-
-Klensin Standards Track [Page 50]
-
-RFC 5321 SMTP October 2008
-
-
- 220 Service ready
-
- 221 Service closing transmission channel
-
- 421 Service not available, closing transmission channel
- (This may be a reply to any command if the service knows it must
- shut down)
-
-
- 250 Requested mail action okay, completed
-
- 251 User not local; will forward to (See Section 3.4)
-
- 252 Cannot VRFY user, but will accept message and attempt delivery
- (See Section 3.5.3)
-
- 455 Server unable to accommodate parameters
-
- 555 MAIL FROM/RCPT TO parameters not recognized or not implemented
-
- 450 Requested mail action not taken: mailbox unavailable (e.g.,
- mailbox busy or temporarily blocked for policy reasons)
-
- 550 Requested action not taken: mailbox unavailable (e.g., mailbox
- not found, no access, or command rejected for policy reasons)
-
- 451 Requested action aborted: error in processing
-
- 551 User not local; please try (See Section 3.4)
-
- 452 Requested action not taken: insufficient system storage
-
- 552 Requested mail action aborted: exceeded storage allocation
-
- 553 Requested action not taken: mailbox name not allowed (e.g.,
- mailbox syntax incorrect)
-
- 354 Start mail input; end with .
-
- 554 Transaction failed (Or, in the case of a connection-opening
- response, "No SMTP service here")
-
-
-
-
-
-
-
-
-
-
-Klensin Standards Track [Page 51]
-
-RFC 5321 SMTP October 2008
-
-
-4.2.3. Reply Codes in Numeric Order
-
- 211 System status, or system help reply
-
- 214 Help message (Information on how to use the receiver or the
- meaning of a particular non-standard command; this reply is useful
- only to the human user)
-
- 220 Service ready
-
- 221 Service closing transmission channel
-
- 250 Requested mail action okay, completed
-
- 251 User not local; will forward to (See Section 3.4)
-
- 252 Cannot VRFY user, but will accept message and attempt delivery
- (See Section 3.5.3)
-
- 354 Start mail input; end with .
-
- 421 Service not available, closing transmission channel
- (This may be a reply to any command if the service knows it must
- shut down)
-
- 450 Requested mail action not taken: mailbox unavailable (e.g.,
- mailbox busy or temporarily blocked for policy reasons)
-
- 451 Requested action aborted: local error in processing
-
- 452 Requested action not taken: insufficient system storage
-
- 455 Server unable to accommodate parameters
-
- 500 Syntax error, command unrecognized (This may include errors such
- as command line too long)
-
- 501 Syntax error in parameters or arguments
-
- 502 Command not implemented (see Section 4.2.4)
-
- 503 Bad sequence of commands
-
- 504 Command parameter not implemented
-
- 550 Requested action not taken: mailbox unavailable (e.g., mailbox
- not found, no access, or command rejected for policy reasons)
-
-
-
-
-Klensin Standards Track [Page 52]
-
-RFC 5321 SMTP October 2008
-
-
- 551 User not local; please try (See Section 3.4)
-
- 552 Requested mail action aborted: exceeded storage allocation
-
- 553 Requested action not taken: mailbox name not allowed (e.g.,
- mailbox syntax incorrect)
-
- 554 Transaction failed (Or, in the case of a connection-opening
- response, "No SMTP service here")
-
- 555 MAIL FROM/RCPT TO parameters not recognized or not implemented
-
-4.2.4. Reply Code 502
-
- Questions have been raised as to when reply code 502 (Command not
- implemented) SHOULD be returned in preference to other codes. 502
- SHOULD be used when the command is actually recognized by the SMTP
- server, but not implemented. If the command is not recognized, code
- 500 SHOULD be returned. Extended SMTP systems MUST NOT list
- capabilities in response to EHLO for which they will return 502 (or
- 500) replies.
-
-4.2.5. Reply Codes after DATA and the Subsequent .
-
- When an SMTP server returns a positive completion status (2yz code)
- after the DATA command is completed with ., it accepts
- responsibility for:
-
- o delivering the message (if the recipient mailbox exists), or
-
- o if attempts to deliver the message fail due to transient
- conditions, retrying delivery some reasonable number of times at
- intervals as specified in Section 4.5.4.
-
- o if attempts to deliver the message fail due to permanent
- conditions, or if repeated attempts to deliver the message fail
- due to transient conditions, returning appropriate notification to
- the sender of the original message (using the address in the SMTP
- MAIL command).
-
- When an SMTP server returns a temporary error status (4yz) code after
- the DATA command is completed with ., it MUST NOT make a
- subsequent attempt to deliver that message. The SMTP client retains
- responsibility for the delivery of that message and may either return
- it to the user or requeue it for a subsequent attempt (see
- Section 4.5.4.1).
-
-
-
-
-
-Klensin Standards Track [Page 53]
-
-RFC 5321 SMTP October 2008
-
-
- The user who originated the message SHOULD be able to interpret the
- return of a transient failure status (by mail message or otherwise)
- as a non-delivery indication, just as a permanent failure would be
- interpreted. If the client SMTP successfully handles these
- conditions, the user will not receive such a reply.
-
- When an SMTP server returns a permanent error status (5yz) code after
- the DATA command is completed with ., it MUST NOT make
- any subsequent attempt to deliver the message. As with temporary
- error status codes, the SMTP client retains responsibility for the
- message, but SHOULD not again attempt delivery to the same server
- without user review of the message and response and appropriate
- intervention.
-
-4.3. Sequencing of Commands and Replies
-
-4.3.1. Sequencing Overview
-
- The communication between the sender and receiver is an alternating
- dialogue, controlled by the sender. As such, the sender issues a
- command and the receiver responds with a reply. Unless other
- arrangements are negotiated through service extensions, the sender
- MUST wait for this response before sending further commands. One
- important reply is the connection greeting. Normally, a receiver
- will send a 220 "Service ready" reply when the connection is
- completed. The sender SHOULD wait for this greeting message before
- sending any commands.
-
- Note: all the greeting-type replies have the official name (the
- fully-qualified primary domain name) of the server host as the first
- word following the reply code. Sometimes the host will have no
- meaningful name. See Section 4.1.3 for a discussion of alternatives
- in these situations.
-
- For example,
-
- 220 ISIF.USC.EDU Service ready
-
- or
-
- 220 mail.example.com SuperSMTP v 6.1.2 Service ready
-
- or
-
- 220 [10.0.0.1] Clueless host service ready
-
- The table below lists alternative success and failure replies for
- each command. These SHOULD be strictly adhered to. A receiver MAY
-
-
-
-Klensin Standards Track [Page 54]
-
-RFC 5321 SMTP October 2008
-
-
- substitute text in the replies, but the meanings and actions implied
- by the code numbers and by the specific command reply sequence MUST
- be preserved.
-
-4.3.2. Command-Reply Sequences
-
- Each command is listed with its usual possible replies. The prefixes
- used before the possible replies are "I" for intermediate, "S" for
- success, and "E" for error. Since some servers may generate other
- replies under special circumstances, and to allow for future
- extension, SMTP clients SHOULD, when possible, interpret only the
- first digit of the reply and MUST be prepared to deal with
- unrecognized reply codes by interpreting the first digit only.
- Unless extended using the mechanisms described in Section 2.2, SMTP
- servers MUST NOT transmit reply codes to an SMTP client that are
- other than three digits or that do not start in a digit between 2 and
- 5 inclusive.
-
- These sequencing rules and, in principle, the codes themselves, can
- be extended or modified by SMTP extensions offered by the server and
- accepted (requested) by the client. However, if the target is more
- precise granularity in the codes, rather than codes for completely
- new purposes, the system described in RFC 3463 [25] SHOULD be used in
- preference to the invention of new codes.
-
- In addition to the codes listed below, any SMTP command can return
- any of the following codes if the corresponding unusual circumstances
- are encountered:
-
- 500 For the "command line too long" case or if the command name was
- not recognized. Note that producing a "command not recognized"
- error in response to the required subset of these commands is a
- violation of this specification. Similarly, producing a "command
- too long" message for a command line shorter than 512 characters
- would violate the provisions of Section 4.5.3.1.4.
-
- 501 Syntax error in command or arguments. In order to provide for
- future extensions, commands that are specified in this document as
- not accepting arguments (DATA, RSET, QUIT) SHOULD return a 501
- message if arguments are supplied in the absence of EHLO-
- advertised extensions.
-
- 421 Service shutting down and closing transmission channel
-
-
-
-
-
-
-
-
-Klensin Standards Track [Page 55]
-
-RFC 5321 SMTP October 2008
-
-
- Specific sequences are:
-
- CONNECTION ESTABLISHMENT
-
- S: 220
- E: 554
-
- EHLO or HELO
-
- S: 250
- E: 504 (a conforming implementation could return this code only
- in fairly obscure cases), 550, 502 (permitted only with an old-
- style server that does not support EHLO)
-
- MAIL
-
- S: 250
- E: 552, 451, 452, 550, 553, 503, 455, 555
-
- RCPT
-
- S: 250, 251 (but see Section 3.4 for discussion of 251 and 551)
- E: 550, 551, 552, 553, 450, 451, 452, 503, 455, 555
-
- DATA
-
- I: 354 -> data -> S: 250
-
- E: 552, 554, 451, 452
-
- E: 450, 550 (rejections for policy reasons)
-
- E: 503, 554
-
- RSET
-
- S: 250
-
- VRFY
-
- S: 250, 251, 252
- E: 550, 551, 553, 502, 504
-
- EXPN
-
- S: 250, 252
- E: 550, 500, 502, 504
-
-
-
-
-Klensin Standards Track [Page 56]
-
-RFC 5321 SMTP October 2008
-
-
- HELP
-
- S: 211, 214
- E: 502, 504
-
- NOOP
-
- S: 250
-
- QUIT
-
- S: 221
-
-4.4. Trace Information
-
- When an SMTP server receives a message for delivery or further
- processing, it MUST insert trace ("time stamp" or "Received")
- information at the beginning of the message content, as discussed in
- Section 4.1.1.4.
-
- This line MUST be structured as follows:
-
- o The FROM clause, which MUST be supplied in an SMTP environment,
- SHOULD contain both (1) the name of the source host as presented
- in the EHLO command and (2) an address literal containing the IP
- address of the source, determined from the TCP connection.
-
- o The ID clause MAY contain an "@" as suggested in RFC 822, but this
- is not required.
-
- o If the FOR clause appears, it MUST contain exactly one
- entry, even when multiple RCPT commands have been given. Multiple
- s raise some security issues and have been deprecated, see
- Section 7.2.
-
- An Internet mail program MUST NOT change or delete a Received: line
- that was previously added to the message header section. SMTP
- servers MUST prepend Received lines to messages; they MUST NOT change
- the order of existing lines or insert Received lines in any other
- location.
-
- As the Internet grows, comparability of Received header fields is
- important for detecting problems, especially slow relays. SMTP
- servers that create Received header fields SHOULD use explicit
- offsets in the dates (e.g., -0800), rather than time zone names of
- any type. Local time (with an offset) SHOULD be used rather than UT
- when feasible. This formulation allows slightly more information
- about local circumstances to be specified. If UT is needed, the
-
-
-
-Klensin Standards Track [Page 57]
-
-RFC 5321 SMTP October 2008
-
-
- receiver need merely do some simple arithmetic to convert the values.
- Use of UT loses information about the time zone-location of the
- server. If it is desired to supply a time zone name, it SHOULD be
- included in a comment.
-
- When the delivery SMTP server makes the "final delivery" of a
- message, it inserts a return-path line at the beginning of the mail
- data. This use of return-path is required; mail systems MUST support
- it. The return-path line preserves the information in the from the MAIL command. Here, final delivery means the message
- has left the SMTP environment. Normally, this would mean it had been
- delivered to the destination user or an associated mail drop, but in
- some cases it may be further processed and transmitted by another
- mail system.
-
- It is possible for the mailbox in the return path to be different
- from the actual sender's mailbox, for example, if error responses are
- to be delivered to a special error handling mailbox rather than to
- the message sender. When mailing lists are involved, this
- arrangement is common and useful as a means of directing errors to
- the list maintainer rather than the message originator.
-
- The text above implies that the final mail data will begin with a
- return path line, followed by one or more time stamp lines. These
- lines will be followed by the rest of the mail data: first the
- balance of the mail header section and then the body (RFC 5322 [4]).
-
- It is sometimes difficult for an SMTP server to determine whether or
- not it is making final delivery since forwarding or other operations
- may occur after the message is accepted for delivery. Consequently,
- any further (forwarding, gateway, or relay) systems MAY remove the
- return path and rebuild the MAIL command as needed to ensure that
- exactly one such line appears in a delivered message.
-
- A message-originating SMTP system SHOULD NOT send a message that
- already contains a Return-path header field. SMTP servers performing
- a relay function MUST NOT inspect the message data, and especially
- not to the extent needed to determine if Return-path header fields
- are present. SMTP servers making final delivery MAY remove Return-
- path header fields before adding their own.
-
- The primary purpose of the Return-path is to designate the address to
- which messages indicating non-delivery or other mail system failures
- are to be sent. For this to be unambiguous, exactly one return path
- SHOULD be present when the message is delivered. Systems using RFC
- 822 syntax with non-SMTP transports SHOULD designate an unambiguous
- address, associated with the transport envelope, to which error
- reports (e.g., non-delivery messages) should be sent.
-
-
-
-Klensin Standards Track [Page 58]
-
-RFC 5321 SMTP October 2008
-
-
- Historical note: Text in RFC 822 that appears to contradict the use
- of the Return-path header field (or the envelope reverse-path address
- from the MAIL command) as the destination for error messages is not
- applicable on the Internet. The reverse-path address (as copied into
- the Return-path) MUST be used as the target of any mail containing
- delivery error messages.
-
- In particular:
- o a gateway from SMTP -> elsewhere SHOULD insert a return-path
- header field, unless it is known that the "elsewhere" transport
- also uses Internet domain addresses and maintains the envelope
- sender address separately.
-
- o a gateway from elsewhere -> SMTP SHOULD delete any return-path
- header field present in the message, and either copy that
- information to the SMTP envelope or combine it with information
- present in the envelope of the other transport system to construct
- the reverse-path argument to the MAIL command in the SMTP
- envelope.
-
- The server must give special treatment to cases in which the
- processing following the end of mail data indication is only
- partially successful. This could happen if, after accepting several
- recipients and the mail data, the SMTP server finds that the mail
- data could be successfully delivered to some, but not all, of the
- recipients. In such cases, the response to the DATA command MUST be
- an OK reply. However, the SMTP server MUST compose and send an
- "undeliverable mail" notification message to the originator of the
- message.
-
- A single notification listing all of the failed recipients or
- separate notification messages MUST be sent for each failed
- recipient. For economy of processing by the sender, the former
- SHOULD be used when possible. Note that the key difference between
- handling aliases (Section 3.9.1) and forwarding (this subsection) is
- the change to the backward-pointing address in this case. All
- notification messages about undeliverable mail MUST be sent using the
- MAIL command (even if they result from processing the obsolete SEND,
- SOML, or SAML commands) and MUST use a null return path as discussed
- in Section 3.6.
-
- The time stamp line and the return path line are formally defined as
- follows (the definitions for "FWS" and "CFWS" appear in RFC 5322
- [4]):
-
- Return-path-line = "Return-Path:" FWS Reverse-path
-
- Time-stamp-line = "Received:" FWS Stamp
-
-
-
-Klensin Standards Track [Page 59]
-
-RFC 5321 SMTP October 2008
-
-
- Stamp = From-domain By-domain Opt-info [CFWS] ";"
- FWS date-time
- ; where "date-time" is as defined in RFC 5322 [4]
- ; but the "obs-" forms, especially two-digit
- ; years, are prohibited in SMTP and MUST NOT be used.
-
- From-domain = "FROM" FWS Extended-Domain
-
- By-domain = CFWS "BY" FWS Extended-Domain
-
- Extended-Domain = Domain /
- ( Domain FWS "(" TCP-info ")" ) /
- ( address-literal FWS "(" TCP-info ")" )
-
- TCP-info = address-literal / ( Domain FWS address-literal )
- ; Information derived by server from TCP connection
- ; not client EHLO.
-
- Opt-info = [Via] [With] [ID] [For]
- [Additional-Registered-Clauses]
-
- Via = CFWS "VIA" FWS Link
-
- With = CFWS "WITH" FWS Protocol
-
- ID = CFWS "ID" FWS ( Atom / msg-id )
- ; msg-id is defined in RFC 5322 [4]
-
- For = CFWS "FOR" FWS ( Path / Mailbox )
-
- Additional-Registered-Clauses = CFWS Atom FWS String
- ; Additional standard clauses may be
- added in this
- ; location by future standards and
- registration with
- ; IANA. SMTP servers SHOULD NOT use
- unregistered
- ; names. See Section 8.
-
- Link = "TCP" / Addtl-Link
-
- Addtl-Link = Atom
- ; Additional standard names for links are
- ; registered with the Internet Assigned Numbers
- ; Authority (IANA). "Via" is primarily of value
- ; with non-Internet transports. SMTP servers
- ; SHOULD NOT use unregistered names.
-
-
-
-
-Klensin Standards Track [Page 60]
-
-RFC 5321 SMTP October 2008
-
-
- Protocol = "ESMTP" / "SMTP" / Attdl-Protocol
-
- Attdl-Protocol = Atom
- ; Additional standard names for protocols are
- ; registered with the Internet Assigned Numbers
- ; Authority (IANA) in the "mail parameters"
- ; registry [9]. SMTP servers SHOULD NOT
- ; use unregistered names.
-
-4.5. Additional Implementation Issues
-
-4.5.1. Minimum Implementation
-
- In order to make SMTP workable, the following minimum implementation
- MUST be provided by all receivers. The following commands MUST be
- supported to conform to this specification:
-
- EHLO
- HELO
- MAIL
- RCPT
- DATA
- RSET
- NOOP
- QUIT
- VRFY
-
- Any system that includes an SMTP server supporting mail relaying or
- delivery MUST support the reserved mailbox "postmaster" as a case-
- insensitive local name. This postmaster address is not strictly
- necessary if the server always returns 554 on connection opening (as
- described in Section 3.1). The requirement to accept mail for
- postmaster implies that RCPT commands that specify a mailbox for
- postmaster at any of the domains for which the SMTP server provides
- mail service, as well as the special case of "RCPT TO:"
- (with no domain specification), MUST be supported.
-
- SMTP systems are expected to make every reasonable effort to accept
- mail directed to Postmaster from any other system on the Internet.
- In extreme cases -- such as to contain a denial of service attack or
- other breach of security -- an SMTP server may block mail directed to
- Postmaster. However, such arrangements SHOULD be narrowly tailored
- so as to avoid blocking messages that are not part of such attacks.
-
-
-
-
-
-
-
-
-Klensin Standards Track [Page 61]
-
-RFC 5321 SMTP October 2008
-
-
-4.5.2. Transparency
-
- Without some provision for data transparency, the character sequence
- "." ends the mail text and cannot be sent by the user.
- In general, users are not aware of such "forbidden" sequences. To
- allow all user composed text to be transmitted transparently, the
- following procedures are used:
-
- o Before sending a line of mail text, the SMTP client checks the
- first character of the line. If it is a period, one additional
- period is inserted at the beginning of the line.
-
- o When a line of mail text is received by the SMTP server, it checks
- the line. If the line is composed of a single period, it is
- treated as the end of mail indicator. If the first character is a
- period and there are other characters on the line, the first
- character is deleted.
-
- The mail data may contain any of the 128 ASCII characters. All
- characters are to be delivered to the recipient's mailbox, including
- spaces, vertical and horizontal tabs, and other control characters.
- If the transmission channel provides an 8-bit byte (octet) data
- stream, the 7-bit ASCII codes are transmitted, right justified, in
- the octets, with the high-order bits cleared to zero. See
- Section 3.6 for special treatment of these conditions in SMTP systems
- serving a relay function.
-
- In some systems, it may be necessary to transform the data as it is
- received and stored. This may be necessary for hosts that use a
- different character set than ASCII as their local character set, that
- store data in records rather than strings, or which use special
- character sequences as delimiters inside mailboxes. If such
- transformations are necessary, they MUST be reversible, especially if
- they are applied to mail being relayed.
-
-4.5.3. Sizes and Timeouts
-
-4.5.3.1. Size Limits and Minimums
-
- There are several objects that have required minimum/maximum sizes.
- Every implementation MUST be able to receive objects of at least
- these sizes. Objects larger than these sizes SHOULD be avoided when
- possible. However, some Internet mail constructs such as encoded
- X.400 addresses (RFC 2156 [35]) will often require larger objects.
- Clients MAY attempt to transmit these, but MUST be prepared for a
- server to reject them if they cannot be handled by it. To the
- maximum extent possible, implementation techniques that impose no
- limits on the length of these objects should be used.
-
-
-
-Klensin Standards Track [Page 62]
-
-RFC 5321 SMTP October 2008
-
-
- Extensions to SMTP may involve the use of characters that occupy more
- than a single octet each. This section therefore specifies lengths
- in octets where absolute lengths, rather than character counts, are
- intended.
-
-4.5.3.1.1. Local-part
-
- The maximum total length of a user name or other local-part is 64
- octets.
-
-4.5.3.1.2. Domain
-
- The maximum total length of a domain name or number is 255 octets.
-
-4.5.3.1.3. Path
-
- The maximum total length of a reverse-path or forward-path is 256
- octets (including the punctuation and element separators).
-
-4.5.3.1.4. Command Line
-
- The maximum total length of a command line including the command word
- and the is 512 octets. SMTP extensions may be used to
- increase this limit.
-
-4.5.3.1.5. Reply Line
-
- The maximum total length of a reply line including the reply code and
- the is 512 octets. More information may be conveyed through
- multiple-line replies.
-
-4.5.3.1.6. Text Line
-
- The maximum total length of a text line including the is 1000
- octets (not counting the leading dot duplicated for transparency).
- This number may be increased by the use of SMTP Service Extensions.
-
-4.5.3.1.7. Message Content
-
- The maximum total length of a message content (including any message
- header section as well as the message body) MUST BE at least 64K
- octets. Since the introduction of Internet Standards for multimedia
- mail (RFC 2045 [21]), message lengths on the Internet have grown
- dramatically, and message size restrictions should be avoided if at
- all possible. SMTP server systems that must impose restrictions
- SHOULD implement the "SIZE" service extension of RFC 1870 [10], and
- SMTP client systems that will send large messages SHOULD utilize it
- when possible.
-
-
-
-Klensin Standards Track [Page 63]
-
-RFC 5321 SMTP October 2008
-
-
-4.5.3.1.8. Recipients Buffer
-
- The minimum total number of recipients that MUST be buffered is 100
- recipients. Rejection of messages (for excessive recipients) with
- fewer than 100 RCPT commands is a violation of this specification.
- The general principle that relaying SMTP server MUST NOT, and
- delivery SMTP servers SHOULD NOT, perform validation tests on message
- header fields suggests that messages SHOULD NOT be rejected based on
- the total number of recipients shown in header fields. A server that
- imposes a limit on the number of recipients MUST behave in an orderly
- fashion, such as rejecting additional addresses over its limit rather
- than silently discarding addresses previously accepted. A client
- that needs to deliver a message containing over 100 RCPT commands
- SHOULD be prepared to transmit in 100-recipient "chunks" if the
- server declines to accept more than 100 recipients in a single
- message.
-
-4.5.3.1.9. Treatment When Limits Exceeded
-
- Errors due to exceeding these limits may be reported by using the
- reply codes. Some examples of reply codes are:
-
- 500 Line too long.
-
- or
-
- 501 Path too long
-
- or
-
- 452 Too many recipients (see below)
-
- or
-
- 552 Too much mail data.
-
-4.5.3.1.10. Too Many Recipients Code
-
- RFC 821 [1] incorrectly listed the error where an SMTP server
- exhausts its implementation limit on the number of RCPT commands
- ("too many recipients") as having reply code 552. The correct reply
- code for this condition is 452. Clients SHOULD treat a 552 code in
- this case as a temporary, rather than permanent, failure so the logic
- below works.
-
- When a conforming SMTP server encounters this condition, it has at
- least 100 successful RCPT commands in its recipients buffer. If the
- server is able to accept the message, then at least these 100
-
-
-
-Klensin Standards Track [Page 64]
-
-RFC 5321 SMTP October 2008
-
-
- addresses will be removed from the SMTP client's queue. When the
- client attempts retransmission of those addresses that received 452
- responses, at least 100 of these will be able to fit in the SMTP
- server's recipients buffer. Each retransmission attempt that is able
- to deliver anything will be able to dispose of at least 100 of these
- recipients.
-
- If an SMTP server has an implementation limit on the number of RCPT
- commands and this limit is exhausted, it MUST use a response code of
- 452 (but the client SHOULD also be prepared for a 552, as noted
- above). If the server has a configured site-policy limitation on the
- number of RCPT commands, it MAY instead use a 5yz response code. In
- particular, if the intent is to prohibit messages with more than a
- site-specified number of recipients, rather than merely limit the
- number of recipients in a given mail transaction, it would be
- reasonable to return a 503 response to any DATA command received
- subsequent to the 452 (or 552) code or to simply return the 503 after
- DATA without returning any previous negative response.
-
-4.5.3.2. Timeouts
-
- An SMTP client MUST provide a timeout mechanism. It MUST use per-
- command timeouts rather than somehow trying to time the entire mail
- transaction. Timeouts SHOULD be easily reconfigurable, preferably
- without recompiling the SMTP code. To implement this, a timer is set
- for each SMTP command and for each buffer of the data transfer. The
- latter means that the overall timeout is inherently proportional to
- the size of the message.
-
- Based on extensive experience with busy mail-relay hosts, the minimum
- per-command timeout values SHOULD be as follows:
-
-4.5.3.2.1. Initial 220 Message: 5 Minutes
-
- An SMTP client process needs to distinguish between a failed TCP
- connection and a delay in receiving the initial 220 greeting message.
- Many SMTP servers accept a TCP connection but delay delivery of the
- 220 message until their system load permits more mail to be
- processed.
-
-4.5.3.2.2. MAIL Command: 5 Minutes
-
-4.5.3.2.3. RCPT Command: 5 Minutes
-
- A longer timeout is required if processing of mailing lists and
- aliases is not deferred until after the message was accepted.
-
-
-
-
-
-Klensin Standards Track [Page 65]
-
-RFC 5321 SMTP October 2008
-
-
-4.5.3.2.4. DATA Initiation: 2 Minutes
-
- This is while awaiting the "354 Start Input" reply to a DATA command.
-
-4.5.3.2.5. Data Block: 3 Minutes
-
- This is while awaiting the completion of each TCP SEND call
- transmitting a chunk of data.
-
-4.5.3.2.6. DATA Termination: 10 Minutes.
-
- This is while awaiting the "250 OK" reply. When the receiver gets
- the final period terminating the message data, it typically performs
- processing to deliver the message to a user mailbox. A spurious
- timeout at this point would be very wasteful and would typically
- result in delivery of multiple copies of the message, since it has
- been successfully sent and the server has accepted responsibility for
- delivery. See Section 6.1 for additional discussion.
-
-4.5.3.2.7. Server Timeout: 5 Minutes.
-
- An SMTP server SHOULD have a timeout of at least 5 minutes while it
- is awaiting the next command from the sender.
-
-4.5.4. Retry Strategies
-
- The common structure of a host SMTP implementation includes user
- mailboxes, one or more areas for queuing messages in transit, and one
- or more daemon processes for sending and receiving mail. The exact
- structure will vary depending on the needs of the users on the host
- and the number and size of mailing lists supported by the host. We
- describe several optimizations that have proved helpful, particularly
- for mailers supporting high traffic levels.
-
- Any queuing strategy MUST include timeouts on all activities on a
- per-command basis. A queuing strategy MUST NOT send error messages
- in response to error messages under any circumstances.
-
-4.5.4.1. Sending Strategy
-
- The general model for an SMTP client is one or more processes that
- periodically attempt to transmit outgoing mail. In a typical system,
- the program that composes a message has some method for requesting
- immediate attention for a new piece of outgoing mail, while mail that
- cannot be transmitted immediately MUST be queued and periodically
- retried by the sender. A mail queue entry will include not only the
- message itself but also the envelope information.
-
-
-
-
-Klensin Standards Track [Page 66]
-
-RFC 5321 SMTP October 2008
-
-
- The sender MUST delay retrying a particular destination after one
- attempt has failed. In general, the retry interval SHOULD be at
- least 30 minutes; however, more sophisticated and variable strategies
- will be beneficial when the SMTP client can determine the reason for
- non-delivery.
-
- Retries continue until the message is transmitted or the sender gives
- up; the give-up time generally needs to be at least 4-5 days. It MAY
- be appropriate to set a shorter maximum number of retries for non-
- delivery notifications and equivalent error messages than for
- standard messages. The parameters to the retry algorithm MUST be
- configurable.
-
- A client SHOULD keep a list of hosts it cannot reach and
- corresponding connection timeouts, rather than just retrying queued
- mail items.
-
- Experience suggests that failures are typically transient (the target
- system or its connection has crashed), favoring a policy of two
- connection attempts in the first hour the message is in the queue,
- and then backing off to one every two or three hours.
-
- The SMTP client can shorten the queuing delay in cooperation with the
- SMTP server. For example, if mail is received from a particular
- address, it is likely that mail queued for that host can now be sent.
- Application of this principle may, in many cases, eliminate the
- requirement for an explicit "send queues now" function such as ETRN,
- RFC 1985 [36].
-
- The strategy may be further modified as a result of multiple
- addresses per host (see below) to optimize delivery time versus
- resource usage.
-
- An SMTP client may have a large queue of messages for each
- unavailable destination host. If all of these messages were retried
- in every retry cycle, there would be excessive Internet overhead and
- the sending system would be blocked for a long period. Note that an
- SMTP client can generally determine that a delivery attempt has
- failed only after a timeout of several minutes, and even a one-minute
- timeout per connection will result in a very large delay if retries
- are repeated for dozens, or even hundreds, of queued messages to the
- same host.
-
- At the same time, SMTP clients SHOULD use great care in caching
- negative responses from servers. In an extreme case, if EHLO is
- issued multiple times during the same SMTP connection, different
- answers may be returned by the server. More significantly, 5yz
- responses to the MAIL command MUST NOT be cached.
-
-
-
-Klensin Standards Track [Page 67]
-
-RFC 5321 SMTP October 2008
-
-
- When a mail message is to be delivered to multiple recipients, and
- the SMTP server to which a copy of the message is to be sent is the
- same for multiple recipients, then only one copy of the message
- SHOULD be transmitted. That is, the SMTP client SHOULD use the
- command sequence: MAIL, RCPT, RCPT, ..., RCPT, DATA instead of the
- sequence: MAIL, RCPT, DATA, ..., MAIL, RCPT, DATA. However, if there
- are very many addresses, a limit on the number of RCPT commands per
- MAIL command MAY be imposed. This efficiency feature SHOULD be
- implemented.
-
- Similarly, to achieve timely delivery, the SMTP client MAY support
- multiple concurrent outgoing mail transactions. However, some limit
- may be appropriate to protect the host from devoting all its
- resources to mail.
-
-4.5.4.2. Receiving Strategy
-
- The SMTP server SHOULD attempt to keep a pending listen on the SMTP
- port (specified by IANA as port 25) at all times. This requires the
- support of multiple incoming TCP connections for SMTP. Some limit
- MAY be imposed, but servers that cannot handle more than one SMTP
- transaction at a time are not in conformance with the intent of this
- specification.
-
- As discussed above, when the SMTP server receives mail from a
- particular host address, it could activate its own SMTP queuing
- mechanisms to retry any mail pending for that host address.
-
-4.5.5. Messages with a Null Reverse-Path
-
- There are several types of notification messages that are required by
- existing and proposed Standards to be sent with a null reverse-path,
- namely non-delivery notifications as discussed in Section 3.7, other
- kinds of Delivery Status Notifications (DSNs, RFC 3461 [32]), and
- Message Disposition Notifications (MDNs, RFC 3798 [37]). All of
- these kinds of messages are notifications about a previous message,
- and they are sent to the reverse-path of the previous mail message.
- (If the delivery of such a notification message fails, that usually
- indicates a problem with the mail system of the host to which the
- notification message is addressed. For this reason, at some hosts
- the MTA is set up to forward such failed notification messages to
- someone who is able to fix problems with the mail system, e.g., via
- the postmaster alias.)
-
- All other types of messages (i.e., any message which is not required
- by a Standards-Track RFC to have a null reverse-path) SHOULD be sent
- with a valid, non-null reverse-path.
-
-
-
-
-Klensin Standards Track [Page 68]
-
-RFC 5321 SMTP October 2008
-
-
- Implementers of automated email processors should be careful to make
- sure that the various kinds of messages with a null reverse-path are
- handled correctly. In particular, such systems SHOULD NOT reply to
- messages with a null reverse-path, and they SHOULD NOT add a non-null
- reverse-path, or change a null reverse-path to a non-null one, to
- such messages when forwarding.
-
-5. Address Resolution and Mail Handling
-
-5.1. Locating the Target Host
-
- Once an SMTP client lexically identifies a domain to which mail will
- be delivered for processing (as described in Sections 2.3.5 and 3.6),
- a DNS lookup MUST be performed to resolve the domain name (RFC 1035
- [2]). The names are expected to be fully-qualified domain names
- (FQDNs): mechanisms for inferring FQDNs from partial names or local
- aliases are outside of this specification. Due to a history of
- problems, SMTP servers used for initial submission of messages SHOULD
- NOT make such inferences (Message Submission Servers [18] have
- somewhat more flexibility) and intermediate (relay) SMTP servers MUST
- NOT make them.
-
- The lookup first attempts to locate an MX record associated with the
- name. If a CNAME record is found, the resulting name is processed as
- if it were the initial name. If a non-existent domain error is
- returned, this situation MUST be reported as an error. If a
- temporary error is returned, the message MUST be queued and retried
- later (see Section 4.5.4.1). If an empty list of MXs is returned,
- the address is treated as if it was associated with an implicit MX
- RR, with a preference of 0, pointing to that host. If MX records are
- present, but none of them are usable, or the implicit MX is unusable,
- this situation MUST be reported as an error.
-
- If one or more MX RRs are found for a given name, SMTP systems MUST
- NOT utilize any address RRs associated with that name unless they are
- located using the MX RRs; the "implicit MX" rule above applies only
- if there are no MX records present. If MX records are present, but
- none of them are usable, this situation MUST be reported as an error.
-
- When a domain name associated with an MX RR is looked up and the
- associated data field obtained, the data field of that response MUST
- contain a domain name. That domain name, when queried, MUST return
- at least one address record (e.g., A or AAAA RR) that gives the IP
- address of the SMTP server to which the message should be directed.
- Any other response, specifically including a value that will return a
- CNAME record when queried, lies outside the scope of this Standard.
- The prohibition on labels in the data that resolve to CNAMEs is
- discussed in more detail in RFC 2181, Section 10.3 [38].
-
-
-
-Klensin Standards Track [Page 69]
-
-RFC 5321 SMTP October 2008
-
-
- When the lookup succeeds, the mapping can result in a list of
- alternative delivery addresses rather than a single address, because
- of multiple MX records, multihoming, or both. To provide reliable
- mail transmission, the SMTP client MUST be able to try (and retry)
- each of the relevant addresses in this list in order, until a
- delivery attempt succeeds. However, there MAY also be a configurable
- limit on the number of alternate addresses that can be tried. In any
- case, the SMTP client SHOULD try at least two addresses.
-
- Two types of information are used to rank the host addresses:
- multiple MX records, and multihomed hosts.
-
- MX records contain a preference indication that MUST be used in
- sorting if more than one such record appears (see below). Lower
- numbers are more preferred than higher ones. If there are multiple
- destinations with the same preference and there is no clear reason to
- favor one (e.g., by recognition of an easily reached address), then
- the sender-SMTP MUST randomize them to spread the load across
- multiple mail exchangers for a specific organization.
-
- The destination host (perhaps taken from the preferred MX record) may
- be multihomed, in which case the domain name resolver will return a
- list of alternative IP addresses. It is the responsibility of the
- domain name resolver interface to have ordered this list by
- decreasing preference if necessary, and the SMTP sender MUST try them
- in the order presented.
-
- Although the capability to try multiple alternative addresses is
- required, specific installations may want to limit or disable the use
- of alternative addresses. The question of whether a sender should
- attempt retries using the different addresses of a multihomed host
- has been controversial. The main argument for using the multiple
- addresses is that it maximizes the probability of timely delivery,
- and indeed sometimes the probability of any delivery; the counter-
- argument is that it may result in unnecessary resource use. Note
- that resource use is also strongly determined by the sending strategy
- discussed in Section 4.5.4.1.
-
- If an SMTP server receives a message with a destination for which it
- is a designated Mail eXchanger, it MAY relay the message (potentially
- after having rewritten the MAIL FROM and/or RCPT TO addresses), make
- final delivery of the message, or hand it off using some mechanism
- outside the SMTP-provided transport environment. Of course, neither
- of the latter require that the list of MX records be examined
- further.
-
- If it determines that it should relay the message without rewriting
- the address, it MUST sort the MX records to determine candidates for
-
-
-
-Klensin Standards Track [Page 70]
-
-RFC 5321 SMTP October 2008
-
-
- delivery. The records are first ordered by preference, with the
- lowest-numbered records being most preferred. The relay host MUST
- then inspect the list for any of the names or addresses by which it
- might be known in mail transactions. If a matching record is found,
- all records at that preference level and higher-numbered ones MUST be
- discarded from consideration. If there are no records left at that
- point, it is an error condition, and the message MUST be returned as
- undeliverable. If records do remain, they SHOULD be tried, best
- preference first, as described above.
-
-5.2. IPv6 and MX Records
-
- In the contemporary Internet, SMTP clients and servers may be hosted
- on IPv4 systems, IPv6 systems, or dual-stack systems that are
- compatible with either version of the Internet Protocol. The host
- domains to which MX records point may, consequently, contain "A RR"s
- (IPv4), "AAAA RR"s (IPv6), or any combination of them. While RFC
- 3974 [39] discusses some operational experience in mixed
- environments, it was not comprehensive enough to justify
- standardization, and some of its recommendations appear to be
- inconsistent with this specification. The appropriate actions to be
- taken either will depend on local circumstances, such as performance
- of the relevant networks and any conversions that might be necessary,
- or will be obvious (e.g., an IPv6-only client need not attempt to
- look up A RRs or attempt to reach IPv4-only servers). Designers of
- SMTP implementations that might run in IPv6 or dual-stack
- environments should study the procedures above, especially the
- comments about multihomed hosts, and, preferably, provide mechanisms
- to facilitate operational tuning and mail interoperability between
- IPv4 and IPv6 systems while considering local circumstances.
-
-6. Problem Detection and Handling
-
-6.1. Reliable Delivery and Replies by Email
-
- When the receiver-SMTP accepts a piece of mail (by sending a "250 OK"
- message in response to DATA), it is accepting responsibility for
- delivering or relaying the message. It must take this responsibility
- seriously. It MUST NOT lose the message for frivolous reasons, such
- as because the host later crashes or because of a predictable
- resource shortage. Some reasons that are not considered frivolous
- are discussed in the next subsection and in Section 7.8.
-
- If there is a delivery failure after acceptance of a message, the
- receiver-SMTP MUST formulate and mail a notification message. This
- notification MUST be sent using a null ("<>") reverse-path in the
- envelope. The recipient of this notification MUST be the address
- from the envelope return path (or the Return-Path: line). However,
-
-
-
-Klensin Standards Track [Page 71]
-
-RFC 5321 SMTP October 2008
-
-
- if this address is null ("<>"), the receiver-SMTP MUST NOT send a
- notification. Obviously, nothing in this section can or should
- prohibit local decisions (i.e., as part of the same system
- environment as the receiver-SMTP) to log or otherwise transmit
- information about null address events locally if that is desired. If
- the address is an explicit source route, it MUST be stripped down to
- its final hop.
-
- For example, suppose that an error notification must be sent for a
- message that arrived with:
-
- MAIL FROM:<@a,@b:user@d>
-
- The notification message MUST be sent using:
-
- RCPT TO:
-
- Some delivery failures after the message is accepted by SMTP will be
- unavoidable. For example, it may be impossible for the receiving
- SMTP server to validate all the delivery addresses in RCPT command(s)
- due to a "soft" domain system error, because the target is a mailing
- list (see earlier discussion of RCPT), or because the server is
- acting as a relay and has no immediate access to the delivering
- system.
-
- To avoid receiving duplicate messages as the result of timeouts, a
- receiver-SMTP MUST seek to minimize the time required to respond to
- the final . end of data indicator. See RFC 1047 [40] for
- a discussion of this problem.
-
-6.2. Unwanted, Unsolicited, and "Attack" Messages
-
- Utility and predictability of the Internet mail system requires that
- messages that can be delivered should be delivered, regardless of any
- syntax or other faults associated with those messages and regardless
- of their content. If they cannot be delivered, and cannot be
- rejected by the SMTP server during the SMTP transaction, they should
- be "bounced" (returned with non-delivery notification messages) as
- described above. In today's world, in which many SMTP server
- operators have discovered that the quantity of undesirable bulk email
- vastly exceeds the quantity of desired mail and in which accepting a
- message may trigger additional undesirable traffic by providing
- verification of the address, those principles may not be practical.
-
- As discussed in Section 7.8 and Section 7.9 below, dropping mail
- without notification of the sender is permitted in practice.
- However, it is extremely dangerous and violates a long tradition and
- community expectations that mail is either delivered or returned. If
-
-
-
-Klensin Standards Track [Page 72]
-
-RFC 5321 SMTP October 2008
-
-
- silent message-dropping is misused, it could easily undermine
- confidence in the reliability of the Internet's mail systems. So
- silent dropping of messages should be considered only in those cases
- where there is very high confidence that the messages are seriously
- fraudulent or otherwise inappropriate.
-
- To stretch the principle of delivery if possible even further, it may
- be a rational policy to not deliver mail that has an invalid return
- address, although the history of the network is that users are
- typically better served by delivering any message that can be
- delivered. Reliably determining that a return address is invalid can
- be a difficult and time-consuming process, especially if the putative
- sending system is not directly accessible or does not fully and
- accurately support VRFY and, even if a "drop messages with invalid
- return addresses" policy is adopted, it SHOULD be applied only when
- there is near-certainty that the return addresses are, in fact,
- invalid.
-
- Conversely, if a message is rejected because it is found to contain
- hostile content (a decision that is outside the scope of an SMTP
- server as defined in this document), rejection ("bounce") messages
- SHOULD NOT be sent unless the receiving site is confident that those
- messages will be usefully delivered. The preference and default in
- these cases is to avoid sending non-delivery messages when the
- incoming message is determined to contain hostile content.
-
-6.3. Loop Detection
-
- Simple counting of the number of "Received:" header fields in a
- message has proven to be an effective, although rarely optimal,
- method of detecting loops in mail systems. SMTP servers using this
- technique SHOULD use a large rejection threshold, normally at least
- 100 Received entries. Whatever mechanisms are used, servers MUST
- contain provisions for detecting and stopping trivial loops.
-
-6.4. Compensating for Irregularities
-
- Unfortunately, variations, creative interpretations, and outright
- violations of Internet mail protocols do occur; some would suggest
- that they occur quite frequently. The debate as to whether a well-
- behaved SMTP receiver or relay should reject a malformed message,
- attempt to pass it on unchanged, or attempt to repair it to increase
- the odds of successful delivery (or subsequent reply) began almost
- with the dawn of structured network mail and shows no signs of
- abating. Advocates of rejection claim that attempted repairs are
- rarely completely adequate and that rejection of bad messages is the
- only way to get the offending software repaired. Advocates of
- "repair" or "deliver no matter what" argue that users prefer that
-
-
-
-Klensin Standards Track [Page 73]
-
-RFC 5321 SMTP October 2008
-
-
- mail go through it if at all possible and that there are significant
- market pressures in that direction. In practice, these market
- pressures may be more important to particular vendors than strict
- conformance to the standards, regardless of the preference of the
- actual developers.
-
- The problems associated with ill-formed messages were exacerbated by
- the introduction of the split-UA mail reading protocols (Post Office
- Protocol (POP) version 2 [15], Post Office Protocol (POP) version 3
- [16], IMAP version 2 [41], and PCMAIL [42]). These protocols
- encouraged the use of SMTP as a posting (message submission)
- protocol, and SMTP servers as relay systems for these client hosts
- (which are often only intermittently connected to the Internet).
- Historically, many of those client machines lacked some of the
- mechanisms and information assumed by SMTP (and indeed, by the mail
- format protocol, RFC 822 [28]). Some could not keep adequate track
- of time; others had no concept of time zones; still others could not
- identify their own names or addresses; and, of course, none could
- satisfy the assumptions that underlay RFC 822's conception of
- authenticated addresses.
-
- In response to these weak SMTP clients, many SMTP systems now
- complete messages that are delivered to them in incomplete or
- incorrect form. This strategy is generally considered appropriate
- when the server can identify or authenticate the client, and there
- are prior agreements between them. By contrast, there is at best
- great concern about fixes applied by a relay or delivery SMTP server
- that has little or no knowledge of the user or client machine. Many
- of these issues are addressed by using a separate protocol, such as
- that defined in RFC 4409 [18], for message submission, rather than
- using originating SMTP servers for that purpose.
-
- The following changes to a message being processed MAY be applied
- when necessary by an originating SMTP server, or one used as the
- target of SMTP as an initial posting (message submission) protocol:
-
- o Addition of a message-id field when none appears
-
- o Addition of a date, time, or time zone when none appears
-
- o Correction of addresses to proper FQDN format
-
- The less information the server has about the client, the less likely
- these changes are to be correct and the more caution and conservatism
- should be applied when considering whether or not to perform fixes
- and how. These changes MUST NOT be applied by an SMTP server that
- provides an intermediate relay function.
-
-
-
-
-Klensin Standards Track [Page 74]
-
-RFC 5321 SMTP October 2008
-
-
- In all cases, properly operating clients supplying correct
- information are preferred to corrections by the SMTP server. In all
- cases, documentation SHOULD be provided in trace header fields and/or
- header field comments for actions performed by the servers.
-
-7. Security Considerations
-
-7.1. Mail Security and Spoofing
-
- SMTP mail is inherently insecure in that it is feasible for even
- fairly casual users to negotiate directly with receiving and relaying
- SMTP servers and create messages that will trick a naive recipient
- into believing that they came from somewhere else. Constructing such
- a message so that the "spoofed" behavior cannot be detected by an
- expert is somewhat more difficult, but not sufficiently so as to be a
- deterrent to someone who is determined and knowledgeable.
- Consequently, as knowledge of Internet mail increases, so does the
- knowledge that SMTP mail inherently cannot be authenticated, or
- integrity checks provided, at the transport level. Real mail
- security lies only in end-to-end methods involving the message
- bodies, such as those that use digital signatures (see RFC 1847 [43]
- and, e.g., Pretty Good Privacy (PGP) in RFC 4880 [44] or Secure/
- Multipurpose Internet Mail Extensions (S/MIME) in RFC 3851 [45]).
-
- Various protocol extensions and configuration options that provide
- authentication at the transport level (e.g., from an SMTP client to
- an SMTP server) improve somewhat on the traditional situation
- described above. However, in general, they only authenticate one
- server to another rather than a chain of relays and servers, much
- less authenticating users or user machines. Consequently, unless
- they are accompanied by careful handoffs of responsibility in a
- carefully designed trust environment, they remain inherently weaker
- than end-to-end mechanisms that use digitally signed messages rather
- than depending on the integrity of the transport system.
-
- Efforts to make it more difficult for users to set envelope return
- path and header "From" fields to point to valid addresses other than
- their own are largely misguided: they frustrate legitimate
- applications in which mail is sent by one user on behalf of another,
- in which error (or normal) replies should be directed to a special
- address, or in which a single message is sent to multiple recipients
- on different hosts. (Systems that provide convenient ways for users
- to alter these header fields on a per-message basis should attempt to
- establish a primary and permanent mailbox address for the user so
- that Sender header fields within the message data can be generated
- sensibly.)
-
-
-
-
-
-Klensin Standards Track [Page 75]
-
-RFC 5321 SMTP October 2008
-
-
- This specification does not further address the authentication issues
- associated with SMTP other than to advocate that useful functionality
- not be disabled in the hope of providing some small margin of
- protection against a user who is trying to fake mail.
-
-7.2. "Blind" Copies
-
- Addresses that do not appear in the message header section may appear
- in the RCPT commands to an SMTP server for a number of reasons. The
- two most common involve the use of a mailing address as a "list
- exploder" (a single address that resolves into multiple addresses)
- and the appearance of "blind copies". Especially when more than one
- RCPT command is present, and in order to avoid defeating some of the
- purpose of these mechanisms, SMTP clients and servers SHOULD NOT copy
- the full set of RCPT command arguments into the header section,
- either as part of trace header fields or as informational or private-
- extension header fields. Since this rule is often violated in
- practice, and cannot be enforced, sending SMTP systems that are aware
- of "bcc" use MAY find it helpful to send each blind copy as a
- separate message transaction containing only a single RCPT command.
-
- There is no inherent relationship between either "reverse" (from
- MAIL, SAML, etc., commands) or "forward" (RCPT) addresses in the SMTP
- transaction ("envelope") and the addresses in the header section.
- Receiving systems SHOULD NOT attempt to deduce such relationships and
- use them to alter the header section of the message for delivery.
- The popular "Apparently-to" header field is a violation of this
- principle as well as a common source of unintended information
- disclosure and SHOULD NOT be used.
-
-7.3. VRFY, EXPN, and Security
-
- As discussed in Section 3.5, individual sites may want to disable
- either or both of VRFY or EXPN for security reasons (see below). As
- a corollary to the above, implementations that permit this MUST NOT
- appear to have verified addresses that are not, in fact, verified.
- If a site disables these commands for security reasons, the SMTP
- server MUST return a 252 response, rather than a code that could be
- confused with successful or unsuccessful verification.
-
- Returning a 250 reply code with the address listed in the VRFY
- command after having checked it only for syntax violates this rule.
- Of course, an implementation that "supports" VRFY by always returning
- 550 whether or not the address is valid is equally not in
- conformance.
-
- On the public Internet, the contents of mailing lists have become
- popular as an address information source for so-called "spammers."
-
-
-
-Klensin Standards Track [Page 76]
-
-RFC 5321 SMTP October 2008
-
-
- The use of EXPN to "harvest" addresses has increased as list
- administrators have installed protections against inappropriate uses
- of the lists themselves. However, VRFY and EXPN are still useful for
- authenticated users and within an administrative domain. For
- example, VRFY and EXPN are useful for performing internal audits of
- how email gets routed to check and to make sure no one is
- automatically forwarding sensitive mail outside the organization.
- Sites implementing SMTP authentication may choose to make VRFY and
- EXPN available only to authenticated requestors. Implementations
- SHOULD still provide support for EXPN, but sites SHOULD carefully
- evaluate the tradeoffs.
-
- Whether disabling VRFY provides any real marginal security depends on
- a series of other conditions. In many cases, RCPT commands can be
- used to obtain the same information about address validity. On the
- other hand, especially in situations where determination of address
- validity for RCPT commands is deferred until after the DATA command
- is received, RCPT may return no information at all, while VRFY is
- expected to make a serious attempt to determine validity before
- generating a response code (see discussion above).
-
-7.4. Mail Rerouting Based on the 251 and 551 Response Codes
-
- Before a client uses the 251 or 551 reply codes from a RCPT command
- to automatically update its future behavior (e.g., updating the
- user's address book), it should be certain of the server's
- authenticity. If it does not, it may be subject to a man in the
- middle attack.
-
-7.5. Information Disclosure in Announcements
-
- There has been an ongoing debate about the tradeoffs between the
- debugging advantages of announcing server type and version (and,
- sometimes, even server domain name) in the greeting response or in
- response to the HELP command and the disadvantages of exposing
- information that might be useful in a potential hostile attack. The
- utility of the debugging information is beyond doubt. Those who
- argue for making it available point out that it is far better to
- actually secure an SMTP server rather than hope that trying to
- conceal known vulnerabilities by hiding the server's precise identity
- will provide more protection. Sites are encouraged to evaluate the
- tradeoff with that issue in mind; implementations SHOULD minimally
- provide for making type and version information available in some way
- to other network hosts.
-
-
-
-
-
-
-
-Klensin Standards Track [Page 77]
-
-RFC 5321 SMTP October 2008
-
-
-7.6. Information Disclosure in Trace Fields
-
- In some circumstances, such as when mail originates from within a LAN
- whose hosts are not directly on the public Internet, trace
- ("Received") header fields produced in conformance with this
- specification may disclose host names and similar information that
- would not normally be available. This ordinarily does not pose a
- problem, but sites with special concerns about name disclosure should
- be aware of it. Also, the optional FOR clause should be supplied
- with caution or not at all when multiple recipients are involved lest
- it inadvertently disclose the identities of "blind copy" recipients
- to others.
-
-7.7. Information Disclosure in Message Forwarding
-
- As discussed in Section 3.4, use of the 251 or 551 reply codes to
- identify the replacement address associated with a mailbox may
- inadvertently disclose sensitive information. Sites that are
- concerned about those issues should ensure that they select and
- configure servers appropriately.
-
-7.8. Resistance to Attacks
-
- In recent years, there has been an increase of attacks on SMTP
- servers, either in conjunction with attempts to discover addresses
- for sending unsolicited messages or simply to make the servers
- inaccessible to others (i.e., as an application-level denial of
- service attack). While the means of doing so are beyond the scope of
- this Standard, rational operational behavior requires that servers be
- permitted to detect such attacks and take action to defend
- themselves. For example, if a server determines that a large number
- of RCPT TO commands are being sent, most or all with invalid
- addresses, as part of such an attack, it would be reasonable for the
- server to close the connection after generating an appropriate number
- of 5yz (normally 550) replies.
-
-7.9. Scope of Operation of SMTP Servers
-
- It is a well-established principle that an SMTP server may refuse to
- accept mail for any operational or technical reason that makes sense
- to the site providing the server. However, cooperation among sites
- and installations makes the Internet possible. If sites take
- excessive advantage of the right to reject traffic, the ubiquity of
- email availability (one of the strengths of the Internet) will be
- threatened; considerable care should be taken and balance maintained
- if a site decides to be selective about the traffic it will accept
- and process.
-
-
-
-
-Klensin Standards Track [Page 78]
-
-RFC 5321 SMTP October 2008
-
-
- In recent years, use of the relay function through arbitrary sites
- has been used as part of hostile efforts to hide the actual origins
- of mail. Some sites have decided to limit the use of the relay
- function to known or identifiable sources, and implementations SHOULD
- provide the capability to perform this type of filtering. When mail
- is rejected for these or other policy reasons, a 550 code SHOULD be
- used in response to EHLO (or HELO), MAIL, or RCPT as appropriate.
-
-8. IANA Considerations
-
- IANA maintains three registries in support of this specification, all
- of which were created for RFC 2821 or earlier. This document expands
- the third one as specified below. The registry references listed are
- as of the time of publication; IANA does not guarantee the locations
- associated with the URLs. The registries are as follows:
-
- o The first, "Simple Mail Transfer Protocol (SMTP) Service
- Extensions" [46], consists of SMTP service extensions with the
- associated keywords, and, as needed, parameters and verbs. As
- specified in Section 2.2.2, no entry may be made in this registry
- that starts in an "X". Entries may be made only for service
- extensions (and associated keywords, parameters, or verbs) that
- are defined in Standards-Track or Experimental RFCs specifically
- approved by the IESG for this purpose.
-
- o The second registry, "Address Literal Tags" [47], consists of
- "tags" that identify forms of domain literals other than those for
- IPv4 addresses (specified in RFC 821 and in this document). The
- initial entry in that registry is for IPv6 addresses (specified in
- this document). Additional literal types require standardization
- before being used; none are anticipated at this time.
-
- o The third, "Mail Transmission Types" [46], established by RFC 821
- and renewed by this specification, is a registry of link and
- protocol identifiers to be used with the "via" and "with"
- subclauses of the time stamp ("Received:" header field) described
- in Section 4.4. Link and protocol identifiers in addition to
- those specified in this document may be registered only by
- standardization or by way of an RFC-documented, IESG-approved,
- Experimental protocol extension. This name space is for
- identification and not limited in size: the IESG is encouraged to
- approve on the basis of clear documentation and a distinct method
- rather than preferences about the properties of the method itself.
-
- An additional subsection has been added to the "VIA link types"
- and "WITH protocol types" subsections of this registry to contain
- registrations of "Additional-registered-clauses" as described
- above. The registry will contain clause names, a description, a
-
-
-
-Klensin Standards Track [Page 79]
-
-RFC 5321 SMTP October 2008
-
-
- summary of the syntax of the associated String, and a reference.
- As new clauses are defined, they may, in principle, specify
- creation of their own registries if the Strings consist of
- reserved terms or keywords rather than less restricted strings.
- As with link and protocol identifiers, additional clauses may be
- registered only by standardization or by way of an RFC-documented,
- IESG-approved, Experimental protocol extension. The additional
- clause name space is for identification and is not limited in
- size: the IESG is encouraged to approve on the basis of clear
- documentation, actual use or strong signs that the clause will be
- used, and a distinct requirement rather than preferences about the
- properties of the clause itself.
-
- In addition, if additional trace header fields (i.e., in addition to
- Return-path and Received) are ever created, those trace fields MUST
- be added to the IANA registry established by BCP 90 (RFC 3864) [11]
- for use with RFC 5322 [4].
-
-9. Acknowledgments
-
- Many people contributed to the development of RFC 2821. That
- document should be consulted for those acknowledgments. For the
- present document, the editor and the community owe thanks to Dawn
- Mann and Tony Hansen who assisted in the very painful process of
- editing and converting the internal format of the document from one
- system to another.
-
- Neither this document nor RFC 2821 would have been possible without
- the many contribution and insights of the late Jon Postel. Those
- contributions of course include the original specification of SMTP in
- RFC 821. A considerable quantity of text from RFC 821 still appears
- in this document as do several of Jon's original examples that have
- been updated only as needed to reflect other changes in the
- specification.
-
- Many people made comments or suggestions on the mailing list or in
- notes to the author. Important corrections or clarifications were
- suggested by several people, including Matti Aarnio, Glenn Anderson,
- Derek J. Balling, Alex van den Bogaerdt, Stephane Bortzmeyer, Vint
- Cerf, Jutta Degener, Steve Dorner, Lisa Dusseault, Frank Ellerman,
- Ned Freed, Randy Gellens, Sabahattin Gucukoglu, Philip Guenther, Arnt
- Gulbrandsen, Eric Hall, Richard O. Hammer, Tony Hansen, Peter J.
- Holzer, Kari Hurtta, Bryon Roche Kain, Valdis Kletnieks, Mathias
- Koerber, John Leslie, Bruce Lilly, Jeff Macdonald, Mark E. Mallett,
- Mark Martinec, S. Moonesamy, Lyndon Nerenberg, Chris Newman, Douglas
- Otis, Pete Resnick, Robert A. Rosenberg, Vince Sabio, Hector Santos,
- David F. Skoll, Paul Smith, and Brett Watson.
-
-
-
-
-Klensin Standards Track [Page 80]
-
-RFC 5321 SMTP October 2008
-
-
- The efforts of the Area Directors -- Lisa Dusseault, Ted Hardie, and
- Chris Newman -- to get this effort restarted and keep it moving, and
- of an ad hoc committee with the same purpose, are gratefully
- acknowledged. The members of that committee were (in alphabetical
- order) Dave Crocker, Cyrus Daboo, Tony Finch, Ned Freed, Randall
- Gellens, Tony Hansen, the author, and Alexey Melnikov. Tony Hansen
- also acted as ad hoc chair on the mailing list reviewing this
- document; without his efforts, sense of balance and fairness, and
- patience, it clearly would not have been possible.
-
-10. References
-
-10.1. Normative References
-
- [1] Postel, J., "Simple Mail Transfer Protocol", STD 10, RFC 821,
- August 1982.
-
- [2] Mockapetris, P., "Domain names - implementation and
- specification", STD 13, RFC 1035, November 1987.
-
- [3] Braden, R., "Requirements for Internet Hosts - Application and
- Support", STD 3, RFC 1123, October 1989.
-
- [4] Resnick, P., "Internet Message Format", RFC 5322, October 2008.
-
- [5] Bradner, S., "Key words for use in RFCs to Indicate Requirement
- Levels", BCP 14, RFC 2119, March 1997.
-
- [6] American National Standards Institute (formerly United States
- of America Standards Institute), "USA Code for Information
- Interchange", ANSI X3.4-1968, 1968.
-
- ANSI X3.4-1968 has been replaced by newer versions with slight
- modifications, but the 1968 version remains definitive for the
- Internet.
-
- [7] Crocker, D. and P. Overell, "Augmented BNF for Syntax
- Specifications: ABNF", STD 68, RFC 5234, January 2008.
-
- [8] Hinden, R. and S. Deering, "IP Version 6 Addressing
- Architecture", RFC 4291, February 2006.
-
- [9] Newman, C., "ESMTP and LMTP Transmission Types Registration",
- RFC 3848, July 2004.
-
- [10] Klensin, J., Freed, N., and K. Moore, "SMTP Service Extension
- for Message Size Declaration", STD 10, RFC 1870, November 1995.
-
-
-
-
-Klensin Standards Track [Page 81]
-
-RFC 5321 SMTP October 2008
-
-
- [11] Klyne, G., Nottingham, M., and J. Mogul, "Registration
- Procedures for Message Header Fields", BCP 90, RFC 3864,
- September 2004.
-
-10.2. Informative References
-
- [12] Partridge, C., "Mail routing and the domain system", RFC 974,
- January 1986.
-
- [13] Klensin, J., Freed, N., Rose, M., Stefferud, E., and D.
- Crocker, "SMTP Service Extensions", STD 10, RFC 1869,
- November 1995.
-
- [14] Klensin, J., "Simple Mail Transfer Protocol", RFC 2821,
- April 2001.
-
- [15] Butler, M., Postel, J., Chase, D., Goldberger, J., and J.
- Reynolds, "Post Office Protocol: Version 2", RFC 937,
- February 1985.
-
- [16] Myers, J. and M. Rose, "Post Office Protocol - Version 3",
- STD 53, RFC 1939, May 1996.
-
- [17] Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION
- 4rev1", RFC 3501, March 2003.
-
- [18] Gellens, R. and J. Klensin, "Message Submission for Mail",
- RFC 4409, April 2006.
-
- [19] Freed, N., "SMTP Service Extension for Command Pipelining",
- STD 60, RFC 2920, September 2000.
-
- [20] Vaudreuil, G., "SMTP Service Extensions for Transmission of
- Large and Binary MIME Messages", RFC 3030, December 2000.
-
- [21] Freed, N. and N. Borenstein, "Multipurpose Internet Mail
- Extensions (MIME) Part One: Format of Internet Message Bodies",
- RFC 2045, November 1996.
-
- [22] Klensin, J., Freed, N., Rose, M., Stefferud, E., and D.
- Crocker, "SMTP Service Extension for 8bit-MIMEtransport",
- RFC 1652, July 1994.
-
- [23] Moore, K., "MIME (Multipurpose Internet Mail Extensions) Part
- Three: Message Header Extensions for Non-ASCII Text", RFC 2047,
- November 1996.
-
-
-
-
-
-Klensin Standards Track [Page 82]
-
-RFC 5321 SMTP October 2008
-
-
- [24] Freed, N. and K. Moore, "MIME Parameter Value and Encoded Word
- Extensions: Character Sets, Languages, and Continuations",
- RFC 2231, November 1997.
-
- [25] Vaudreuil, G., "Enhanced Mail System Status Codes", RFC 3463,
- January 2003.
-
- [26] Hansen, T. and J. Klensin, "A Registry for SMTP Enhanced Mail
- System Status Codes", BCP 138, RFC 5248, June 2008.
-
- [27] Freed, N., "Behavior of and Requirements for Internet
- Firewalls", RFC 2979, October 2000.
-
- [28] Crocker, D., "Standard for the format of ARPA Internet text
- messages", STD 11, RFC 822, August 1982.
-
- [29] Wong, M. and W. Schlitt, "Sender Policy Framework (SPF) for
- Authorizing Use of Domains in E-Mail, Version 1", RFC 4408,
- April 2006.
-
- [30] Fenton, J., "Analysis of Threats Motivating DomainKeys
- Identified Mail (DKIM)", RFC 4686, September 2006.
-
- [31] Allman, E., Callas, J., Delany, M., Libbey, M., Fenton, J., and
- M. Thomas, "DomainKeys Identified Mail (DKIM) Signatures",
- RFC 4871, May 2007.
-
- [32] Moore, K., "Simple Mail Transfer Protocol (SMTP) Service
- Extension for Delivery Status Notifications (DSNs)", RFC 3461,
- January 2003.
-
- [33] Moore, K. and G. Vaudreuil, "An Extensible Message Format for
- Delivery Status Notifications", RFC 3464, January 2003.
-
- [34] Postel, J. and J. Reynolds, "File Transfer Protocol", STD 9,
- RFC 959, October 1985.
-
- [35] Kille, S., "MIXER (Mime Internet X.400 Enhanced Relay): Mapping
- between X.400 and RFC 822/MIME", RFC 2156, January 1998.
-
- [36] De Winter, J., "SMTP Service Extension for Remote Message Queue
- Starting", RFC 1985, August 1996.
-
- [37] Hansen, T. and G. Vaudreuil, "Message Disposition
- Notification", RFC 3798, May 2004.
-
- [38] Elz, R. and R. Bush, "Clarifications to the DNS Specification",
- RFC 2181, July 1997.
-
-
-
-Klensin Standards Track [Page 83]
-
-RFC 5321 SMTP October 2008
-
-
- [39] Nakamura, M. and J. Hagino, "SMTP Operational Experience in
- Mixed IPv4/v6 Environments", RFC 3974, January 2005.
-
- [40] Partridge, C., "Duplicate messages and SMTP", RFC 1047,
- February 1988.
-
- [41] Crispin, M., "Interactive Mail Access Protocol: Version 2",
- RFC 1176, August 1990.
-
- [42] Lambert, M., "PCMAIL: A distributed mail system for personal
- computers", RFC 1056, June 1988.
-
- [43] Galvin, J., Murphy, S., Crocker, S., and N. Freed, "Security
- Multiparts for MIME: Multipart/Signed and Multipart/Encrypted",
- RFC 1847, October 1995.
-
- [44] Callas, J., Donnerhacke, L., Finney, H., Shaw, D., and R.
- Thayer, "OpenPGP Message Format", RFC 4880, November 2007.
-
- [45] Ramsdell, B., "Secure/Multipurpose Internet Mail Extensions
- (S/MIME) Version 3.1 Message Specification", RFC 3851,
- July 2004.
-
- [46] Internet Assigned Number Authority (IANA), "IANA Mail
- Parameters", 2007,
- .
-
- [47] Internet Assigned Number Authority (IANA), "Address Literal
- Tags", 2007,
- .
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Klensin Standards Track [Page 84]
-
-RFC 5321 SMTP October 2008
-
-
-Appendix A. TCP Transport Service
-
- The TCP connection supports the transmission of 8-bit bytes. The
- SMTP data is 7-bit ASCII characters. Each character is transmitted
- as an 8-bit byte with the high-order bit cleared to zero. Service
- extensions may modify this rule to permit transmission of full 8-bit
- data bytes as part of the message body, or, if specifically designed
- to do so, in SMTP commands or responses.
-
-Appendix B. Generating SMTP Commands from RFC 822 Header Fields
-
- Some systems use an RFC 822 header section (only) in a mail
- submission protocol, or otherwise generate SMTP commands from RFC 822
- header fields when such a message is handed to an MTA from a UA.
- While the MTA-UA protocol is a private matter, not covered by any
- Internet Standard, there are problems with this approach. For
- example, there have been repeated problems with proper handling of
- "bcc" copies and redistribution lists when information that
- conceptually belongs to the mail envelope is not separated early in
- processing from header field information (and kept separate).
-
- It is recommended that the UA provide its initial ("submission
- client") MTA with an envelope separate from the message itself.
- However, if the envelope is not supplied, SMTP commands SHOULD be
- generated as follows:
-
- 1. Each recipient address from a TO, CC, or BCC header field SHOULD
- be copied to a RCPT command (generating multiple message copies
- if that is required for queuing or delivery). This includes any
- addresses listed in a RFC 822 "group". Any BCC header fields
- SHOULD then be removed from the header section. Once this
- process is completed, the remaining header fields SHOULD be
- checked to verify that at least one TO, CC, or BCC header field
- remains. If none do, then a BCC header field with no additional
- information SHOULD be inserted as specified in [4].
-
- 2. The return address in the MAIL command SHOULD, if possible, be
- derived from the system's identity for the submitting (local)
- user, and the "From:" header field otherwise. If there is a
- system identity available, it SHOULD also be copied to the Sender
- header field if it is different from the address in the From
- header field. (Any Sender header field that was already there
- SHOULD be removed.) Systems may provide a way for submitters to
- override the envelope return address, but may want to restrict
- its use to privileged users. This will not prevent mail forgery,
- but may lessen its incidence; see Section 7.1.
-
-
-
-
-
-Klensin Standards Track [Page 85]
-
-RFC 5321 SMTP October 2008
-
-
- When an MTA is being used in this way, it bears responsibility for
- ensuring that the message being transmitted is valid. The mechanisms
- for checking that validity, and for handling (or returning) messages
- that are not valid at the time of arrival, are part of the MUA-MTA
- interface and not covered by this specification.
-
- A submission protocol based on Standard RFC 822 information alone
- MUST NOT be used to gateway a message from a foreign (non-SMTP) mail
- system into an SMTP environment. Additional information to construct
- an envelope must come from some source in the other environment,
- whether supplemental header fields or the foreign system's envelope.
-
- Attempts to gateway messages using only their header "To" and "Cc"
- fields have repeatedly caused mail loops and other behavior adverse
- to the proper functioning of the Internet mail environment. These
- problems have been especially common when the message originates from
- an Internet mailing list and is distributed into the foreign
- environment using envelope information. When these messages are then
- processed by a header-section-only remailer, loops back to the
- Internet environment (and the mailing list) are almost inevitable.
-
-Appendix C. Source Routes
-
- Historically, the was a reverse source routing list of
- hosts and a source mailbox. The first host in the was
- historically the host sending the MAIL command; today, source routes
- SHOULD NOT appear in the reverse-path. Similarly, the
- may be a source routing lists of hosts and a destination mailbox.
- However, in general, the SHOULD contain only a mailbox
- and domain name, relying on the domain name system to supply routing
- information if required. The use of source routes is deprecated (see
- Appendix F.2); while servers MUST be prepared to receive and handle
- them as discussed in Section 3.3 and Appendix F.2, clients SHOULD NOT
- transmit them and this section is included in the current
- specification only to provide context. It has been modified somewhat
- from the material in RFC 821 to prevent server actions that might
- confuse clients or subsequent servers that do not expect a full
- source route implementation.
-
- For relay purposes, the forward-path may be a source route of the
- form "@ONE,@TWO:JOE@THREE", where ONE, TWO, and THREE MUST be fully-
- qualified domain names. This form is used to emphasize the
- distinction between an address and a route. The mailbox (here, JOE@
- THREE) is an absolute address, and the route is information about how
- to get there. The two concepts should not be confused.
-
- If source routes are used, RFC 821 and the text below should be
- consulted for the mechanisms for constructing and updating the
-
-
-
-Klensin Standards Track [Page 86]
-
-RFC 5321 SMTP October 2008
-
-
- forward-path. A server that is reached by means of a source route
- (e.g., its domain name appears first in the list in the forward-path)
- MUST remove its domain name from any forward-paths in which that
- domain name appears before forwarding the message and MAY remove all
- other source routing information. The reverse-path SHOULD NOT be
- updated by servers conforming to this specification.
-
- Notice that the forward-path and reverse-path appear in the SMTP
- commands and replies, but not necessarily in the message. That is,
- there is no need for these paths and especially this syntax to appear
- in the "To:" , "From:", "CC:", etc. fields of the message header
- section. Conversely, SMTP servers MUST NOT derive final message
- routing information from message header fields.
-
- When the list of hosts is present despite the recommendations above,
- it is a "reverse" source route and indicates that the mail was
- relayed through each host on the list (the first host in the list was
- the most recent relay). This list is used as a source route to
- return non-delivery notices to the sender. If, contrary to the
- recommendations here, a relay host adds itself to the beginning of
- the list, it MUST use its name as known in the transport environment
- to which it is relaying the mail rather than that of the transport
- environment from which the mail came (if they are different). Note
- that a situation could easily arise in which some relay hosts add
- their names to the reverse source route and others do not, generating
- discontinuities in the routing list. This is another reason why
- servers needing to return a message SHOULD ignore the source route
- entirely and simply use the domain as specified in the Mailbox.
-
-Appendix D. Scenarios
-
- This section presents complete scenarios of several types of SMTP
- sessions. In the examples, "C:" indicates what is said by the SMTP
- client, and "S:" indicates what is said by the SMTP server.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Klensin Standards Track [Page 87]
-
-RFC 5321 SMTP October 2008
-
-
-D.1. A Typical SMTP Transaction Scenario
-
- This SMTP example shows mail sent by Smith at host bar.com, and to
- Jones, Green, and Brown at host foo.com. Here we assume that host
- bar.com contacts host foo.com directly. The mail is accepted for
- Jones and Brown. Green does not have a mailbox at host foo.com.
-
- S: 220 foo.com Simple Mail Transfer Service Ready
- C: EHLO bar.com
- S: 250-foo.com greets bar.com
- S: 250-8BITMIME
- S: 250-SIZE
- S: 250-DSN
- S: 250 HELP
- C: MAIL FROM:
- S: 250 OK
- C: RCPT TO:
- S: 250 OK
- C: RCPT TO:
- S: 550 No such user here
- C: RCPT TO:
- S: 250 OK
- C: DATA
- S: 354 Start mail input; end with .
- C: Blah blah blah...
- C: ...etc. etc. etc.
- C: .
- S: 250 OK
- C: QUIT
- S: 221 foo.com Service closing transmission channel
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Klensin Standards Track [Page 88]
-
-RFC 5321 SMTP October 2008
-
-
-D.2. Aborted SMTP Transaction Scenario
-
- S: 220 foo.com Simple Mail Transfer Service Ready
- C: EHLO bar.com
- S: 250-foo.com greets bar.com
- S: 250-8BITMIME
- S: 250-SIZE
- S: 250-DSN
- S: 250 HELP
- C: MAIL FROM:
- S: 250 OK
- C: RCPT TO:
- S: 250 OK
- C: RCPT TO:
- S: 550 No such user here
- C: RSET
- S: 250 OK
- C: QUIT
- S: 221 foo.com Service closing transmission channel
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Klensin Standards Track [Page 89]
-
-RFC 5321 SMTP October 2008
-
-
-D.3. Relayed Mail Scenario
-
- Step 1 -- Source Host to Relay Host
-
- The source host performs a DNS lookup on XYZ.COM (the destination
- address) and finds DNS MX records specifying xyz.com as the best
- preference and foo.com as a lower preference. It attempts to open a
- connection to xyz.com and fails. It then opens a connection to
- foo.com, with the following dialogue:
-
- S: 220 foo.com Simple Mail Transfer Service Ready
- C: EHLO bar.com
- S: 250-foo.com greets bar.com
- S: 250-8BITMIME
- S: 250-SIZE
- S: 250-DSN
- S: 250 HELP
- C: MAIL FROM:
- S: 250 OK
- C: RCPT TO:
- S: 250 OK
- C: DATA
- S: 354 Start mail input; end with .
- C: Date: Thu, 21 May 1998 05:33:29 -0700
- C: From: John Q. Public
- C: Subject: The Next Meeting of the Board
- C: To: Jones@xyz.com
- C:
- C: Bill:
- C: The next meeting of the board of directors will be
- C: on Tuesday.
- C: John.
- C: .
- S: 250 OK
- C: QUIT
- S: 221 foo.com Service closing transmission channel
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Klensin Standards Track [Page 90]
-
-RFC 5321 SMTP October 2008
-
-
- Step 2 -- Relay Host to Destination Host
-
- foo.com, having received the message, now does a DNS lookup on
- xyz.com. It finds the same set of MX records, but cannot use the one
- that points to itself (or to any other host as a worse preference).
- It tries to open a connection to xyz.com itself and succeeds. Then
- we have:
-
- S: 220 xyz.com Simple Mail Transfer Service Ready
- C: EHLO foo.com
- S: 250 xyz.com is on the air
- C: MAIL FROM:
- S: 250 OK
- C: RCPT TO:
- S: 250 OK
- C: DATA
- S: 354 Start mail input; end with .
- C: Received: from bar.com by foo.com ; Thu, 21 May 1998
- C: 05:33:29 -0700
- C: Date: Thu, 21 May 1998 05:33:22 -0700
- C: From: John Q. Public
- C: Subject: The Next Meeting of the Board
- C: To: Jones@xyz.com
- C:
- C: Bill:
- C: The next meeting of the board of directors will be
- C: on Tuesday.
- C: John.
- C: .
- S: 250 OK
- C: QUIT
- S: 221 foo.com Service closing transmission channel
-
-
-
-
-
-
-
-